Wie mache ich `head` und` tail` bei null-getrennten Eingaben in bash?

18

findDer Befehl kann Dateinamen als durch Nullen getrennte Zeichenfolgen ausgeben ( -print0sofern angegeben) und xargsdiese mit -0aktivierter Option verwenden. Aber zwischendurch , ist es schwer , dass die Sammlung von Dateien zu manipulieren - sortBefehl hat -zSchalter, die es ermöglicht , diese Dateien zu sortieren, aber headund tailnicht in Anspruch genommen hat.

Wie kann ich tun headund tailauf diese Null-getrennte Eingänge auf bequeme Art und Weise? (Ich kann immer ein kurzes & langsames Ruby-Skript erstellen, aber ich hoffe, dass es einen besseren Weg gibt.)

Rogach
quelle

Antworten:

21

GNU headund tailseit Coreutils Version 8.25 haben eine -zOption dafür.

Bei älteren Versionen oder für Nicht-GNU - Systeme können Sie versuchen, Swap \0und \n:

find ... -print0 |
  tr '\0\n' '\n\0' |
  head |
  tr '\0\n' '\n\0'

Beachten Sie, dass einige headImplementierungen nicht mit NUL - Zeichen umgehen kann (und sie sind nicht erforderlich , um von POSIX), aber wo Träger finden -print0, headund Text - Dienstprogramme im Allgemeinen NUL - Zeichen unterstützen.

Sie können auch eine Funktion verwenden, um einen beliebigen Befehl zwischen den beiden trWerten zu setzen:

nul_terminated() {
  tr '\0\n' '\n\0' | "$@" | tr '\0\n' '\n\0'
}

find ... -print0 | nul_terminated tail -n 12 | xargs -r0 ...

Denken Sie daran, dass unter nul_terminateda \0ein Newline-Zeichen steht. So zum Beispiel zu ersetzen \ndurch _:

find . -depth -name $'*\n*' -print0 | nul_terminated sed '
  p;h;s,.*/,,;s/\x0/_/g;H;g;s,[^/]*\n,,' | xargs -r0n2 mv

( \x0ist auch eine GNU-Erweiterung).

Wenn Sie mehr als einen Filterbefehl ausführen müssen , haben Sie folgende Möglichkeiten:

find ... -print0 |
  nul_terminated cmd1 |
  nul_terminated cmd2 | xargs -r0 ...

Das heißt aber, ein paar redundante trBefehle auszuführen. Alternativ können Sie Folgendes ausführen:

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
Stéphane Chazelas
quelle
2
Besiegt dies nicht den Hauptgrund¹ für die Verwendung, \x0anstatt \ndie Werte abzugrenzen? (¹, damit Sie mit Werten umgehen können, die möglicherweise enthalten sind \n)
Mittwoch,
@Thedward, nein, im Gegensatz dazu -print0 | tr '\n\0' '\0\n'gibt es Zeilen, die die Dateipfade darstellen, in die Zeilenumbrüche konvertiert wurden \0. Wenn Sie also die erste Zeile mit nehmen head -n 1und das \0s wieder mit in Zeilenumbrüche umwandeln tr '\0\n' '\n\0', erhalten Sie den ersten Dateipfad, der durch die eingebetteten Zeilenumbrüche NUL-getrennt ist.
Stéphane Chazelas