Usando a substituição de processos para enganar programas que esperam arquivos, com extensões específicas como argumento?

Usando a substituição de processos para enganar programas que esperam arquivos, com extensões específicas como argumento?

Aqui está meu caso de uso: o utilitário de linha de comando meltpode aceitar um nome de arquivo, com a extensão .meltna linha de comando, e abri-lo; por exemplo, este é um test_p.meltarquivo adequado:

colour:blue
out=24

colour:red
out=48

... que abre e brinca com melt test_p.melt.

Agora, o problema é que .meltos 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.meltarquivo comentado:

# master comment here

colour:blue  # this is blue!
out=24

colour:red
out=48

Abrindo isso meltdiretamente 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 sede simplesmente forneça isso ao meltaplicativo. 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 meltacontece é que ele processa argv[i]diretamente; e no caso de um arquivo, é necessário ver uma .meltextensã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 meltpara 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 .meltarquivo 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 ~/workestá a raiz da árvore que contém seus .meltarquivos e ~/bin/uncomment-meltestá

#!/bin/sh
sed 's/#.*$//' "$1"

Então, se você tiver um arquivo ~/work/test_c.meltcom comentários, poderá executar o melt ~/uncommented-melt/test_c.melt.

Outros sistemas de arquivos FUSE potencialmente úteis:

  • Executar— permite criar um driver FUSE simples com scripts de shell
  • AVFSou outros sistemas de arquivos FUSE que descompactam arquivos de forma transparente: defina a remoção de comentários como uma regra de descompactação.

Responder2

Com o zshshell, você pode usar a =(...)forma de substituição de processo (que usa arquivos temporários em vez de /dev/fd/xarquivos 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 infopáginas estão instaladas, pode ser necessário instalar um zsh-docpacote) 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 sedno 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.shmeltfile, que na verdade é um script que contém meu código de script bashcomentado ; melttorne este arquivo executável chmod +x test.shmelt; depois de editar o script, execute-o como ./test.shmelt.

test.meltAo ser executado, ele criará um arquivo "limpo" /tmpe chamará meltesse arquivo. Como meltgeralmente 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:

  1. Tenho um conversor de imagens;
  2. converte de [inserir formato aleatório] para formatos simples como BMP/PNM/TGA;
  3. Quero converter para JPEG, então preciso encadear com ImageMagick convert;
  4. 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/Ne 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]

informação relacionada