Convertir les retours à la ligne en valeurs nulles lors de l'utilisation de tail

20

Comment puis-je modifier la sortie de tailpour utiliser des lignes terminées par null au lieu de retours à la ligne?

Ma question est similaire à celle-ci: comment faire `head` et` tail` sur une entrée délimitée par null dans bash? , mais diffère en ce que je veux faire quelque chose comme:

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

Je n'utilise pas findet ne peux donc pas utiliser-print0

Tout cela pour éviter l'erreur qui se produit dans xargs:

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

Réponses:

26

Si vous voulez que les 10 dernières lignes:

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

Mais avec GNU xargs, vous pouvez également définir le délimiteur sur newline avec:

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

( -0est l'abréviation de -d '\0').

De manière portable, vous pouvez également simplement échapper à chaque personnage:

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

Ou citez chaque ligne:

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

Si vous voulez les 10 derniers enregistrements délimités par NUL myFile.txt(mais ce ne serait pas un fichier texte), vous devez convertir le \nen \0avant d'appeler, tailce qui signifie que le fichier devra être lu en entier:

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

Modifier (puisque vous avez changé le tailen tail -fdans votre question):

Le dernier ci-dessus n'a évidemment aucun sens tail -f.

L' xargs -d '\n'un fonctionnera, mais pour les autres, vous aurez un problème de mise en mémoire tampon. Dans:

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

trmet en mémoire tampon sa sortie lorsqu'il ne va pas à un terminal (ici, un tuyau). IE, il n'écrira rien tant qu'il n'aura pas accumulé un tampon plein (quelque chose comme 8 Ko) de données à écrire. Ce qui signifie myCmdsera appelé par lots.

Sur un système GNU ou FreeBSD, vous pouvez modifier le comportement de mise en mémoire tampon de travec la stdbufcommande:

tail -f myFile.txt | stdbuf -o0 tr '\n' '\0' |
  xargs -r0i myCmd {} arg1 arg2
Stéphane Chazelas
la source
En fait, je voulais utiliser l'option -f sur la queue, qui imprime continuellement les lignes à mesure qu'elles entrent. Je ne pensais pas que cela aurait de l'importance, mais apparemment c'est le cas. Avec l'option -f, votre solution ne fonctionne pas.
Lars
Le tail -f myFile.txt | xargs -r0i -d '\n' myCmd "{}" "||" "||"semble fonctionner! Merci.
Lars
@Lars, désolé, l' -ioption prend un argument facultatif, donc -i0ne fonctionnerait pas. Ils devraient tous fonctionner avec tail -fsauf le dernier, mais attention à cause de la mise en mémoire tampon, il y aura un délai avant d' xargsobtenir son entrée tr. Vous pouvez changer cela en exécutant stdbuf -o0 tr '\n' '\0'au lieu de tr '\n' '\0'.
Stéphane Chazelas