Não é possível fazer a construção xargs funcionar

Não é possível fazer a construção xargs funcionar

Eu tenho um problema estranho comxargs.
eu tenho umxargsconstrução que não funciona, embora quando eu repito o comando, funcione perfeitamente. Meu único forro é o seguinte:

 exiftool -p exifprintformat  -if '$Subject =~/DATA/i' -q  *.pdf |grep pdf |sed 's/ //g'|xargs|xargs -0 -I % pdftk % cat output binder1.pdf  

e a saída

Erro: Não foi possível encontrar o arquivo. Erro: Falha ao abrir o arquivo PDF: 20170105170516234.pdf 20170105173126944.pdf 20170105173209758.pdf 20170621163418079.pdf

  • O exiftoolseleciona todos os pdf que contenham a palavra DATA na tag de assunto,
  • As -p exifprintformatinstruções exiftoolpara imprimir apenas o nome do arquivo,
  • O grepseleciona apenas as linhas com pdf,
  • O sedremove espaços em branco,
  • O primeiro xargtransforma todas as linhas em uma string e o segundo constrói o comando bind) quando executo

exiftool -p exifprintformat -if '$Subject =~/DATA/i' -q *.pdf |grep pdf |sed 's/ //g'|xargs|xargs -I{} echo pdftk {} cat output binder1.pdf

eu recebo

pdftk 20170105170516234.pdf 20170105173126944.pdf 20170105173209758.pdf 20170621163418079.pdf cat output binder1.pdf

que funciona perfeitamente.

Obviamente, estou fazendo algo errado...Mas o quê?

Responder1

Existem várias coisas erradas e uma complexidade desnecessária: -

  1. A chamada dupla xargssignifica que o segundo vê uma única linha de entrada, portanto {}é substituído apenas uma vez por uma única string contendo todos os nomes de arquivos correspondentes, mas echonão mostra essa diferença na saída (compare echo a bcom echo "a b").
  2. O -0argumento significa que xargsprecisa de um '\0'caractere nulo ( ) entre os argumentos de entrada e não há nenhum; isso também força a entrada a ser tratada como um único parâmetro.
  3. Ao gerar apenas o nome do arquivo quando a condição corresponder, você obtém um nome de arquivo por linha, que pode ser canalizado diretamente xargssem a necessidade de grepou sed.
  4. Infelizmente, xargs -Iforça um comando por linha de entrada e não há opção para adicionar parâmetros finais, mas há uma solução simples: adicionar os parâmetros finais ao fluxo de entrada.

Este é um comando simplificado com os parâmetros finais adicionados (testei com uma -ifcondição diferente, não tendo nenhum PDF correspondente): -

{ exiftool -p '${FileName}' -if '$Subject =~/DATA/i' -q *.pdf; \
  echo -e "cat\noutput\nbinder1.pdf"; } | xargs -d'\n' pdftk

A xargs -d'\n'opção faz o comando funcionar quando os nomes dos arquivos possuem espaços em branco incorporados.

Responder2

A página de manual do xargs diz:

-Eu substituo-str

  Replace occurrences of replace-str in the initial-arguments with
  names read from standard input.   Also, unquoted blanks do not
  terminate input items; instead the separator is the newline
  character.  Implies -x and -L 1.

Em outras palavras, você acabará com um único argumento chamado " 20170105170516234.pdf 20170105173126944.pdf 20170105173209758.pdf 20170621163418079.pdf"

Sugiro abandonar completamente o xargs e reordenar seu comando mais ou menos assim:

pdftk $(exiftool -p exifprintformat -if '$Subject =~/DATA/i' -q *.pdf |grep pdf |sed 's/ //g'| tr '\n' ' ') cat output binder1.pdf

Tudo isso pressupõe que você não tenha espaços em seus nomes de arquivos (suposição segura, já que você estava removendo todos os espaços com sed de qualquer maneira).

informação relacionada