Converter novas linhas em delimitado por nulo ao usar cauda

20

Como alterar a saída de tailpara usar linhas terminadas em nulo em vez de novas linhas?

Minha pergunta é semelhante a esta: Como fazer `head` e` tail` em entradas delimitadas por nulo no bash? , mas é diferente porque quero fazer algo como:

tail -f myFile.txt | xargs -i0 myCmd {} "arg1" "arg2"

Não estou usando finde, portanto, não posso usar-print0

Tudo isso é para evitar o erro que ocorre no xargs:

xargs: unmatched double quote;
    by default quotes are special to xargs unless you use the -0 option
Lars
fonte

Respostas:

26

Se você deseja as últimas 10 linhas:

tail myFile.txt | tr '\n' '\0' | xargs -r0i myCmd {} arg1 arg2

Mas com o GNU xargs, você também pode definir o delimitador para nova linha com:

tail myFile.txt | xargs -ri -d '\n' myCmd {} arg1 arg2

( -0é a abreviação de -d '\0').

Portably, você também pode simplesmente escapar de todos os personagens:

tail myFile.txt | sed 's/./\\&/g' | xargs -I{} myCmd {} arg1 arg2

Ou cite cada linha:

tail myFile.txt | sed 's/"/"\\""/g;s/.*/"&"/' | xargs -I{} myCmd {} arg1 arg2

Se você quiser os 10 últimos registros delimitados por NUL de myFile.txt(mas isso não seria um arquivo de texto), será necessário converter o arquivo \npara \0antes de chamar, o tailque significa que o arquivo terá que ser lido completamente:

tr '\n\0' '\0\n' < myFile.txt |
  tail |
  tr '\n\0' '\0\n' |
  xargs -r0i myCmd {} arg1 arg2

Editar (desde que você alterou o tailpara tail -fna sua pergunta):

O último acima, obviamente, não faz sentido tail -f.

O xargs -d '\n'deles irá funcionar, mas para os outros, você vai ter um problema buffering. Em:

tail -f myFile.txt | tr '\n' '\0' | xargs -r0i myCmd {} arg1 arg2

tramortece sua saída quando não vai para um terminal (aqui, um tubo). IE, ele não escreverá nada até que tenha acumulado um buffer completo (algo como 8kiB) de dados para gravação. Quais meios myCmdserão chamados em lotes.

Em um sistema GNU ou FreeBSD, você pode alterar o comportamento do buffer trcom o stdbufcomando:

tail -f myFile.txt | stdbuf -o0 tr '\n' '\0' |
  xargs -r0i myCmd {} arg1 arg2
Stéphane Chazelas
fonte
Na verdade, eu pretendia usar a opção -f na cauda, ​​que imprime continuamente as linhas à medida que elas entram. Eu não achei que isso importaria, mas aparentemente importa. Com a opção -f, sua solução não funciona.
Lars
O tail -f myFile.txt | xargs -r0i -d '\n' myCmd "{}" "||" "||"parece funcionar! Obrigado.
Lars
@ Lars, desculpe, a -iopção aceita um argumento opcional, portanto -i0não funcionaria. Todos eles devem trabalhar, tail -fexceto o último, mas cuidado com o fato de que, devido ao buffer, haverá um atraso antes de xargsreceber sua entrada tr. Você pode mudar isso executando em stdbuf -o0 tr '\n' '\0'vez de tr '\n' '\0'.
Stéphane Chazelas