Criando um arquivo temporário a partir da entrada padrão

Criando um arquivo temporário a partir da entrada padrão

Digamos que eu tenha um fluxo de entrada padrão deconteúdo do arquivoe um comando que espera umnome do arquivocomo argumento e quero executar esse comando em um arquivo composto pelo conteúdo do arquivo do fluxo de entrada padrão.

Por exemplo, em vez do comando

imageviewer mouse.jpg

Eu quero alguma linha mágica magicque torne isso equivalente a

cat mouse.jpg | magic

Como seria isso magicem zshou bash?

De preferência, eu gostaria que parecesse

cat mouse.jpg | submagic | xargs imageviewer

isto é, eu gostaria submagicde criar um arquivo temporário a partir do fluxo de entrada padrão e gerar o nome do arquivo criado.

As linhas magicou submagicdevem ser pipelines de shell usando apenas comandos bash ou zsh, seus componentes internos, GNU coreutils e similares.


Esta é toda a questão. Abaixo estão apenas esclarecimentos e antecedentes porque as pessoas continuaram interpretando mal o que eu quis dizer.


Ok, então pensei ter deixado isso claro, mas parece que não: eurealmentequero ter um pipeline fazendo o equivalente a

imageviewer mouse.jpg

quecomeça exatamentecom cat mouse.jpg | …. Ou seja, eurealmentequererexatamenteuma linha magicou submagicalgo assimexatamenteos pipelines acima funcionam – eu quis dizer minha pergunta literalmente.

Isso significa, em particular, que as seguintes soluções sugeridas não funcionarão:

  • iniciando o pipeline comtmpfile = $(mktemp); cat mouse.jpg | …
  • reescrevendo-o comoimageviewer =(cat mouse.jpg)
  • reescrevendo-o comoecho mouse.jpg | xargs imageviewer
  • usando uma função ou um binário para resolvê-lo, digamos, definindofunction magic () { … }

Pode-se dizer que o que me interessa é se é possível escrever um alias alias magic='…'ou alias submagic='…'que um dos pipelines acima funcione e que a definição desses aliases contenha nada mais do que comandos bash ou zsh, GNU coreutils e similares - nada escrito por mim mesmo.

Outro comentário. Você pensa imageviewerem ser fehou sxivalgo assim.

Fundo. Esta pergunta surgiu quando tentei abrir vários arquivos de imagem anexados a um e-mail usando meu cliente de e-mail neomutt. Neomutt se oferece para marcar arquivos anexados e, em seguida, canalizar o conteúdo do arquivo para uma linha de comando que você pode digitar. Portanto, aqui só posso fornecer uma linha de comando que execute algo em um determinado fluxo de entrada padrão. Foi daí que surgiu a pergunta. Mas não estou interessado no problema original, mas apenas nesta questão.

Responder1

Pelo bashmenos, com o uso de umsubstituição de processo:

utility <( some_other_utility )

Isso se apresentaria utilitycom umnome do arquivo. Ao utilityabrir o arquivo e lê-lo, ele lerá a saída padrão de some_other_utility.


Seu exemplo:

cat mouse.jpg | submagic | xargs imageviewer

Presumo que isso se destina a enviar onome do arquivo mouse.jpgpara imageviewer, pois não faz sentido enviar o conteúdo de um arquivo JPEG por meio de xargs.

Isso poderia ser feito através de apenas

echo 'mouse.jpg' | xargs imageviewer

ou

xargs imageviewer <<<'mouse.jpg'

em bash.

O envio do conteúdo de mouse.jpgto imageviewerpode ser feito com

cat mouse.jpg | imageviewer /dev/stdin

ou, usando a substituição do processo, com

imageviewer <( cat mouse.jpg )

Usando um arquivo temporário:

tmpfile=$(mktemp)
cat mouse.jpg >"$tmpfile"

imageviewer "$tmpfile"

rm "$tmpfile"

Possivelmente,

tmpfile=$(mktemp)
cat mouse.jpg | { cat >"$tmpfile"; echo "$tmpfile"; } | xargs imageviewer
rm "$tmpfile"

Este pipeline depende do fato de que xargsesperaria a execução imagevieweraté ler o nome do arquivo na parte intermediária do pipeline. O nome do arquivo não seria gerado pelo comando intermediário até que o arquivo temporário fosse criado.

Responder2

Após um esclarecimento submagicna pergunta editei a resposta.

Você zshpode criar um arquivo temporário a partir da saída de um comando com a extensão =( ... ). Em contraste com <( ... )o qual pode usar um arquivo de dispositivo como /dev/fd...ou um pipe nomeado, o formulário =( ... )cria um arquivo temporário pesquisável. Verhttp://zsh.sourceforge.net/Doc/Release/Expansion.html#Process-Substitution

Supondo que cat mouse.jpgseja apenas um exemplo para qualquer comando que envie dados de imagem para stdout, você pode usar

imageviewer =(cat mouse.jpg)

Se você precisar que o arquivo temporário criado por zsh tenha uma extensão específica, você pode definir oTMPSUFFIXvariável especial):

(TMPSUFFIX=.jpg; imageviewer =(cat mouse.jpg))

segunda atualização

Se você insiste na sintaxe

cat mouse.jpg | submagic | xargs imageviewer

seria possível criar um script submagicsemelhante aos comandos já propostos na resposta de Kusalananda.

#! /bin/sh

# A fixed name allows multiple runs without creating lots of files and
# allows a simple script to remove the file afterwards.
TMPFILE=/tmp/submagic.tmp.jpg
rm -f "$TMPFILE" && cat > "$TMPFILE" && echo "$TMPFILE"

Em contraste com mecanismos de shell como =( cat mouse.jpg )este, não seriam removidos $TMPFILEapós a execução imageviewer.

Se você puder executar um segundo script após a execução, imageviewerisso poderá remover o arquivo se ele souber o nome.

Roteirosubmagic-cleanup

#! /bin/sh

# A fixed name allows a simple script for cleaning up.
TMPFILE=/tmp/submagic.tmp.jpg
rm -f "$TMPFILE"

Então você poderia correr

cat mouse.jpg | submagic | xargs imageviewer
submagic-cleanup

Responder3

Para atender aos requisitos exatos da sua pergunta, você pode fazer:

cat mouse.jpg | { tf=$(mktemp); cat >"$tf"; echo "$tf"; } | xargs imageviewer

informação relacionada