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

6

Aqui está o 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 arquivo test_p.melt adequado:

colour:blue
out=24

colour:red
out=48

... que é aberto e reproduzido com melt test_p.melt .

Agora, a questão é que .melt arquivos não suportam comentários, o que eu gostaria que eles fizessem (você receberá mensagens de erro para qualquer linha que contenha um argumento não analisável, incluindo aqueles com, digamos, # ) . Então, aqui está um arquivo test_c.melt comentado:

# master comment here

colour:blue  # this is blue!
out=24

colour:red
out=48

Abrir isso em melt gera diretamente:

$ melt test_c.melt
Failed to load "# master comment here"
...

... e não há tela azul mostrada.

Então eu pensei - bem, eu posso colocar comentários de qualquer maneira , e então usar a substituição do processo Bash para filtrar o arquivo com sed , e simplesmente fornecer isso ao aplicativo melt . Primeiro, tentei um teste com cat , o que é 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 verá meus truques:

$ melt <(sed 's/#.*$//' test_c.melt)
Failed to load "/dev/fd/62"
Failed to load "/dev/fd/62"

Basicamente, o derretimento recebeu o nome do arquivo do cachimbo fornecido pelo Bash para a substituição do processo - mas, infelizmente, o que melt faz é que ele processa argv[i] diretamente; e no caso de um arquivo, ele precisa ver uma extensão .melt no nome do arquivo; se isso não acontecer, o processo falhará.

Então, minha pergunta é: como eu poderia usar a substituição de processos - então o nome do arquivo do pipe tem uma extensão específica, neste caso .melt ? Basicamente, como resultado da substituição, eu quero um nome de arquivo pipe de /dev/fd/62.melt , que eu acho que vai passar.

NB: claro, sempre posso fazer:

sed 's/#.*$//' test_c.melt > test_c_temp.melt
melt test_c_temp.melt

... mas primeiro, há dois comandos aqui - e eu quero um duto de uma linha; e para outro, isso abre outro problema para mim, pensando em remover arquivos temporários depois, o que eu não gosto.

Isso é possível com a substituição do processo Bash - ou de alguma forma com as ferramentas padrão do Linux?

    
por sdaau 28.01.2015 / 22:52

4 respostas

3

Uma possibilidade seria apontar melt para um sistema de arquivos que mostre cópias modificadas de arquivos. O FUSE é uma maneira genérica de construir o driver do sistema de arquivos implementado por um programa comum e não requer privilégios. Existem muitos sistemas de arquivos FUSE , e há uma boa chance de que um deles possa ajudá-lo. A idéia é fornecer um ponto de montagem em que ler um arquivo .melt leia o arquivo "real", mas com comentários filtrados.

ScriptFS parece promissor (mas nunca usei isso). Algo como isso deve funcionar:

mkdir ~/uncommented-melt
scriptfs -p "$HOME/bin/uncomment-melt;&*.melt" ~/work ~/uncommented-melt

em que ~/work é a raiz da árvore que contém seus arquivos .melt e ~/bin/uncomment-melt is

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

Em seguida, se você tiver um arquivo ~/work/test_c.melt com comentários, poderá executar melt ~/uncommented-melt/test_c.melt .

Outros possíveis sistemas de arquivos úteis do FUSE:

  • Execfuse - permite criar um driver FUSE simples com scripts de shell
  • AVFS ou outros sistemas de arquivos FUSE que descompactam arquivos de forma transparente: definem a remoção de comentários como uma regra de descompressão.
por 28.01.2015 / 23:14
1

Ok, no meu caso específico, esses tipos de scripts de fusão devem ser interpretados estritamente como argumentos de linha de comandos; então apenas o sed no OP não corta (além disso, existem 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.

Por fim, decidi usar isso: crie um arquivo test.shmelt , que é na verdade um script bash que contém meu código de script melt comentado; tornar este arquivo executável chmod +x test.shmelt ; depois de editar o script, execute-o como ./test.shmelt .

Ao executar, ele criará um arquivo test.melt "limpo" em /tmp e chamará melt nesse arquivo. Como melt normalmente continua rodando no terminal após o final do programa, com um trap no SIGINT, este arquivo temporário pode ser limpo quando o Ctrl-C é pressionado (mas não é necessário).

Dessa forma, ainda tenho comentários; pode editar rapidamente no arquivo de origem e executar a fusão e ver os resultados; e ter um arquivo "limpo" de comentários também, que eu possa usar depois.

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
    
por 23.02.2015 / 17:32
1
Já faz um tempo, mas vou tentar responder a pergunta do título de uma forma que teria sido útil para mim.

Isso está relacionado: Por que a BASH substituição de processo não funciona com alguns comandos?

Então, o problema específico que eu estava tentando resolver era o seguinte:

  1. Eu tenho um conversor de imagem;
  2. converte de [inserir formato aleatório] para formatos simples como BMP / PNM / TGA;
  3. Eu quero converter para JPEG, então preciso encadeá-lo com ImageMagick convert ;
  4. Eu não quero usar arquivos temporários.

Portanto, infelizmente, a ferramenta não gosta de imprimir em stdout / fds / pipes porque deriva o formato de saída da extensão do nome do arquivo de saída. Então, como enganar isso?

Crie um link de software com a extensão apropriada para /dev/fd/N e use isso como "arquivo temporário".

Exemplo:

ln -s /dev/fd/4 temp.pnm
[TOOL] -i [INPUTFILE] -o temp.pnm 4>&1 | convert - [OUTPUT.JPG]
    
por 26.11.2018 / 13:29
0

Com o shell zsh , você pode usar a forma =(...) da substituição do processo (que usa arquivos temporários em vez de /dev/fd/x files e pipes) para os quais você pode especificar um sufixo:

(TMPSUFFIX=.melt; melt =(sed 's/#.*$//' test_c.melt))

Veja info zsh TMPSUFFIX (assumindo que as info páginas estão instaladas, você pode precisar instalar um pacote zsh-doc ) para detalhes.

    
por 26.11.2018 / 14:00