Podczas używania ogona konwertuj znaki nowego wiersza na znak rozdzielany zerami

20

Jak mogę zmienić dane wyjściowe, tailaby używać linii zakończonych znakiem zerowym zamiast nowych linii?

Moje pytanie jest podobne do tego: Jak zrobić `head` i` tail` na wejściu rozdzielanym zerami w bash? , ale różni się tym, że chcę zrobić coś takiego:

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

Nie używam find, więc nie mogę używać-print0

Wszystko po to, aby uniknąć błędu występującego w xargs:

xargs: unmatched double quote;
    by default quotes are special to xargs unless you use the -0 option
Lars
źródło

Odpowiedzi:

26

Jeśli chcesz, aby ostatnie 10 linii:

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

Ale w GNU xargsmożesz również ustawić separator na nowy wiersz za pomocą:

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

( -0jest skrótem od -d '\0').

Przenośnie możesz po prostu uciec każdej postaci:

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

Lub zacytuj każdą linię:

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

Jeśli chcesz 10 ostatnich rozdzielonych NUL-em rekordów myFile.txt(ale wtedy nie byłby to plik tekstowy), musiałbyś przekonwertować go \nna \0przed wywołaniem, tailco oznaczałoby, że plik będzie musiał zostać w pełni odczytany:

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

Edit (ponieważ zmienił tailsię tail -fw swoim pytaniu):

Ostatni powyżej oczywiście nie ma sensu tail -f.

Ten xargs -d '\n'będzie działał, ale w przypadku innych będziesz mieć problem z buforowaniem. W:

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

trbuforuje dane wyjściowe, gdy nie przechodzi ono do terminala (tutaj potoku). IE nie zapisuje niczego, dopóki nie zgromadzi pełnego bufora (coś w rodzaju 8kiB) danych do zapisania. Co oznacza, myCmdże będą wywoływane partiami.

W systemie GNU lub FreeBSD, można zmienić zachowanie buforujące trz stdbufpoleceniem:

tail -f myFile.txt | stdbuf -o0 tr '\n' '\0' |
  xargs -r0i myCmd {} arg1 arg2
Stéphane Chazelas
źródło
Właściwie to chciałem użyć opcji -f na ogonie, która ciągle drukuje linie, gdy się pojawiają. Nie sądziłem, że to będzie miało znaczenie, ale najwyraźniej ma to znaczenie. Z opcją -f twoje rozwiązanie nie działa.
Lars
tail -f myFile.txt | xargs -r0i -d '\n' myCmd "{}" "||" "||"Wydaje się działać! Dzięki.
Lars
@Lars, przepraszam, -iopcja przyjmuje opcjonalny argument, więc -i0nie zadziała. Wszyscy powinni pracować z tail -fwyjątkiem ostatniego, ale uważaj, że z powodu buforowania nastąpi opóźnienie przed uzyskaniem xargsdanych wejściowych tr. Możesz to zmienić, uruchamiając stdbuf -o0 tr '\n' '\0'zamiast tr '\n' '\0'.
Stéphane Chazelas