Aqui está meu caso de uso: o utilitário de linha de comando melt
pode aceitar um nome de arquivo, com a extensão .melt
na linha de comando, e abri-lo; por exemplo, este é um test_p.melt
arquivo adequado:
colour:blue
out=24
colour:red
out=48
... que abre e brinca com melt test_p.melt
.
Agora, o problema é que .melt
os arquivos não suportam comentários, o que eu gostaria que suportassem (você receberá mensagens de erro para qualquer linha que contenha um argumento não analisável, incluindo aquelas com, digamos, a #
). Então aqui está um test_c.melt
arquivo comentado:
# master comment here
colour:blue # this is blue!
out=24
colour:red
out=48
Abrindo isso melt
diretamente dá:
$ melt test_c.melt
Failed to load "# master comment here"
...
... e não há tela azul mostrada.
Então pensei: bem, posso colocar comentáriosde qualquer formae, em seguida, use a substituição do processo Bash para filtrar o arquivo sed
e simplesmente forneça isso ao melt
aplicativo. Primeiro, tentei um teste com cat
, que foi bem-sucedido:
$ cat <(sed 's/#.*$//' test_c.melt)
colour:blue
out=24
colour:red
out=48
... parece bom;mas, se eu tentar isso com melt
, ele perceberá meus truques:
$ melt <(sed 's/#.*$//' test_c.melt)
Failed to load "/dev/fd/62"
Failed to load "/dev/fd/62"
Basicamente, melt obteve o nome do arquivo do pipe Bash fornecido para a substituição do processo - mas infelizmente, o que melt
acontece é que ele processa argv[i]
diretamente; e no caso de um arquivo, é necessário ver uma .melt
extensão no nome do arquivo; caso contrário, o processo falhará.
Então minha pergunta é: como eu poderia usar a substituição de processo - para que o nome do arquivo do pipe tenha uma extensão específica, neste caso .melt
? Basicamente, como resultado da substituição, eu gostaria de um nome de arquivo de pipe /dev/fd/62.melt
, que acho que será aprovado.
NB: claro, sempre posso fazer:
sed 's/#.*$//' test_c.melt > test_c_temp.melt
melt test_c_temp.melt
... mas primeiro, existem dois comandos aqui - e eu gostaria de um pipeline de uma linha; e por outro lado, abre outro problema de eu pensar em remover arquivos temporários depois, o que não gosto.
Isso é possível com a substituição do processo Bash - ou de alguma forma com ferramentas padrão do Linux?
Responder1
Uma possibilidade seria apontar melt
para um sistema de arquivos que mostre cópias modificadas de arquivos.FUSÍVELé uma maneira genérica de construir um driver de sistema de arquivos implementado por um programa comum e não requer privilégios. Hámuitos sistemas de arquivos FUSE ao redor, e há uma boa chance de que um deles possa ajudá-lo. A ideia é fornecer um ponto de montagem onde a leitura de um .melt
arquivo leia o arquivo “real”, mas com os comentários filtrados.
ScriptFSparece promissor (mas nunca usei). Algo assim deve funcionar:
mkdir ~/uncommented-melt
scriptfs -p "$HOME/bin/uncomment-melt;&*.melt" ~/work ~/uncommented-melt
onde ~/work
está a raiz da árvore que contém seus .melt
arquivos e ~/bin/uncomment-melt
está
#!/bin/sh
sed 's/#.*$//' "$1"
Então, se você tiver um arquivo ~/work/test_c.melt
com comentários, poderá executar o melt ~/uncommented-melt/test_c.melt
.
Outros sistemas de arquivos FUSE potencialmente úteis:
Responder2
Com o zsh
shell, você pode usar a =(...)
forma de substituição de processo (que usa arquivos temporários em vez de /dev/fd/x
arquivos e pipes) para a qual você pode especificar um sufixo:
(TMPSUFFIX=.melt; melt =(sed 's/#.*$//' test_c.melt))
Consulte info zsh TMPSUFFIX
(assumindo que as info
páginas estão instaladas, pode ser necessário instalar um zsh-doc
pacote) para obter detalhes.
Responder3
Ok, acontece que no meu caso específico, esse tipo de script de fusão deve ser interpretado estritamente como argumentos de linha de comando; então apenas aquele sed
no OP não é suficiente (além disso, há outras coisas como perfis que podem ser definidos). Então aqui está o que acabei fazendo - provavelmente pode servir de inspiração em outros casos que o título do OP cobriria.
Acabei decidindo usar isto: make a test.shmelt
file, que na verdade é um script que contém meu código de script bash
comentado ; melt
torne este arquivo executável chmod +x test.shmelt
; depois de editar o script, execute-o como ./test.shmelt
.
test.melt
Ao ser executado, ele criará um arquivo "limpo" /tmp
e chamará melt
esse arquivo. Como melt
geralmente continua rodando no terminal após o término do programa, com uma armadilha no SIGINT esse arquivo temporário pode ser limpo quando Ctrl-C é pressionado (mas não é necessário).
Dessa forma, ainda tenho comentários; pode editar rapidamente no arquivo de origem e executar o melt e ver os resultados; e ter um arquivo "limpo" de comentários também, que posso usar mais tarde.
Aqui está o código de test.shmelt
:
#!/bin/bash
# call with: ./test.shmelt
#TMLTFILE="test.melt" # for final export
TMLTFILE="${0%%.shmelt}.melt" # for final export
function finished() { echo ; } ; # use this when testing or montaging to keep exported (tmp) .melt file; uncomment the below to remove the tmp file
#~ function finished() { rm /tmp/"$TMLTFILE"; echo "fin1 $0" ; } ; trap finished SIGINT ;
echo 'Remember `pulseaudio --start` to hear audio with `melt`!'
pulseaudio --check
if [ $? -ne 0 ]; then
pulseaudio --start
fi
DIRNAME=$(readlink -f $(dirname $0))
PROFILE="square_ntsc"
echo "
# the profile doesn't work from here;
# still has to be specified on command line
# but including it here so the path is saved for testing
#~ -profile
#~ ${PROFILE}
-video-track
# can avoid pixmap: here, but that s the producer;
# qimage: also works
# NB it is NOT '-out 1645'; but 'out=1645'!!
/media/myimg/%05d.bmp
in=0
out=1645
#~ length=1645
#~ loop=0
#~ eof=stop
-audio-track
/media/mysnd/snd.wav
in=0
out=1645
#~ loop=0
#~ eof=stop
#-consumer xml # doesn't work here
" | sed -e 's/#.*$//' -e 's/^[[:space:]]*//' -e '/^[[:space:]]*$/d' -e 's/[[:blank:]]*$//' > ${TMLTFILE}
# the sed: remove comments; remove indents; remove empty lines; remove spaces at end of line
# eof: one of: stop, loop, continue or pause (eof=stop)
# to loop, use `melt eof=loop ...` (but make sure first,
# that the edit as a whole stops - use xml to check!)
# due to caching issues, preview pieces (up to ~300 frames) like this:
melt eof=loop -profile ${PROFILE} ${TMLTFILE} in=200 out=400
# must have profile here, for checking w/ -consumer xml (else segfault)
# this command may add additional producers to the xml!:
## melt -profile ${PROFILE} ${TMLTFILE} -consumer xml
# use this to generate xml if needed:
#melt -profile ${PROFILE} $(cat ${TMLTFILE} | tr '\n' ' ') -consumer xml
# if exited normally, cleanup:
finished
Responder4
Já faz um tempo, mas tentarei responder à pergunta do título de uma forma que me seja útil.
Isto está relacionado:Por que a substituição do processo BASH não funciona com alguns comandos?
Então, o problema específico que eu estava tentando resolver era este:
- Tenho um conversor de imagens;
- converte de [inserir formato aleatório] para formatos simples como BMP/PNM/TGA;
- Quero converter para JPEG, então preciso encadear com ImageMagick
convert
; - Não quero usar arquivos temporários.
Então, infelizmente, a ferramenta não gosta de gerar saída para stdout/fds/pipes porque deriva o formato de saída da extensão do nome do arquivo de saída. Então, como enganá-lo?
Crie um link simbólico com a extensão apropriada /dev/fd/N
e use-o como "arquivo temporário".
Exemplo:
ln -s /dev/fd/4 temp.pnm
[TOOL] -i [INPUTFILE] -o temp.pnm 4>&1 | convert - [OUTPUT.JPG]