Como passar vários arquivos em um fluxo para processá-los como um pipe (sem salvar) no lado de recebimento?

3

Eu preciso determinar o tipo de arquivo em um número indeterminado de filestream codificado em base64 vindo de stdin (arquivos de imagem codificados em base64 e codificados).

Um único arquivo seria simplesmente ... | base64 -d | identify - .

O problema de vários arquivos é determinar o EOF para cada arquivo no fluxo. Mesmo se eu separar os arquivos com identify4 antes de enviá-los para stdout, a extremidade de recebimento do canal ( file ou while read REPLY , et al) parecerá não reconhecer que há mais de um arquivo no fluxo (sim, Eu sei que o fluxo é um arquivo, mas eu estava esperando en EOF mid-stream de alguma forma, para vários valores de "alguma forma", trabalho.

Eu tentei ler stdin em um loop read , mas %code% é baseado em linhas, não em arquivo, então parece não funcionar como eu quero.

[editar, depois] Há entre 3 a 10 arquivos com menos de 400 KB, portanto, tamanho e processamento não são um problema para o meu caso de uso, mas estou interessado na questão em geral.

[eidt, later] Estou tentando evitar arquivos tmp (que é minha solução atual), principalmente porque sou filosoficamente contra o uso do sistema de arquivos como um buffer entre dois processos adjacentes quando um fluxo entre processos é muito mais eficiente. Eu sei que soa pomposo, então, para uma solução que precisa funcionar agora, é claro que eu uso arquivos tmp. No entanto, percebi que há uma lacuna no meu conhecimento e estou tentando encontrar a resposta para o caso geral.

    
por Nick Coleman 04.12.2017 / 02:33

2 respostas

1

Even if I separate the files with %bl0ck_qu0te%4 before sending them to stdout ...

Ainda bem que você pode modificar o procedimento de envio. Minha solução é a seguinte:

for f in *.jpg; do echo S; base64 "$f"; echo ""; done |
# the above is just an example sending process
while read dummy; do
  sed -u '/^$/q' | base64 -d | identify -
done

Esclarecimento:

  • O "bloco de arquivo" único começa com uma linha descartável ("S" neste caso) que não transporta dados. Se read não conseguir encontrar uma linha, o comando inteiro será finalizado.
  • sed passa os dados para o decodificador até que haja uma linha vazia (nota: a linha vazia adicional não altera a saída de base64 -d ).
  • É crucial usar sed ( -u flag) sem buffer; caso contrário, um sed poderia ler muito e, eventualmente, descartar o que considera excesso de dados; então o próximo sed (consequentemente, o próximo identify ) não receberia todos os dados que deveria.

Dicas:

  • A linha extra pode conter metadados em vez de "S", como um nome de arquivo ou algo assim (mas cuidado com as novas linhas nos nomes, etc.).
  • Como base64 produz uma saída maior do que sua entrada, convém usar gzip em ambos os lados, especialmente se seu fluxo viaja pela Internet.
por 04.12.2017 / 14:46
1

Isso meio que funciona se você canalizar a entrada para while read com o delimitador definido como $'...'4 (usando a expansão read , pois read não interpreta vazamentos de contrabarras)

for x in *.jpg ; do base64 < "$x" ; echo -e '
for x in *.jpg ; do base64 < "$x" ; echo -e '%pre%4';  done | 
    while read -rd $'%pre%4' file ; do 
        echo "$file" | base64 -d | identify - 
    done
4'; done | while read -rd $'%pre%4' file ; do echo "$file" | base64 -d | identify - done

É muito lento para arquivos maiores, já que o shell não pode saber se algo dentro do loop vai ler o pipe e, portanto, %code% precisa ler byte por byte. Isso provavelmente deve ser implementado em Perl ou em alguma outra linguagem de programação real para que o buffer possa ser controlado exatamente.

    
por 04.12.2017 / 11:14