Verwenden von comm mit NULL-terminierten Datensätzen

Verwenden von comm mit NULL-terminierten Datensätzen

Über ineine Antwortzu einer anderen Frage: Ich wollte eine Struktur ähnlich dieser verwenden, um Dateien zu finden, die in vorkommen, list2aber nicht in vorkommen list1:

( cd dir1 && find . -type f -print0 ) | sort -z > list1
( cd dir2 && find . -type f -print0 ) | sort -z > list2
comm -13 list1 list2

Ich bin jedoch auf ein Hindernis gestoßen, da meine Version von commkeine NULL-terminierten Datensätze verarbeiten kann. (Einige Hintergrundinformationen: Ich übergebe eine berechnete Liste an rm, daher möchte ich insbesondere in der Lage sein, Dateinamen zu verarbeiten, die eine eingebettete neue Zeile enthalten könnten.)

Wenn Sie ein einfaches Beispiel möchten, versuchen Sie dies

mkdir dir1 dir2
touch dir1/{a,b,c} dir2/{a,c,d}
( cd dir1 && find . -type f ) | sort > list1
( cd dir2 && find . -type f ) | sort > list2
comm -13 list1 list2

Ohne NULL-terminierte Zeilen ist die Ausgabe hier das einzelne Element ./d, das nur in vorkommt list2.

Ich möchte es find ... -print0 | sort -zzum Generieren der Listen verwenden können.

Wie kann ich am besten ein Äquivalent zu neu implementieren, commdas die NULL-terminierten Datensätze ausgibt, die in vorkommen, list2aber nicht in list1?

Antwort1

GNU comm(ab GNU Coreutils 8.25) hat jetzt eine -z/ --zero-terminated-Option dafür.

Bei älteren Versionen von GNU commsollten Sie NUL und NL vertauschen können:

comm -13 <(cd dir1 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) \
         <(cd dir2 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) |
  tr '\n\0' '\0\n'

Diese Methode commfunktioniert immer noch mit durch Zeilenumbrüche getrennten Datensätzen, aber mit tatsächlichen Zeilenumbrüchen in der Eingabe, die als NULs codiert sind, sodass wir bei Dateinamen, die Zeilenumbrüche enthalten, immer noch auf der sicheren Seite sind.

Möglicherweise möchten Sie auch das Gebietsschema auf festlegen, Cda zumindest auf GNU-Systemen und in den meisten UTF-8-Gebietsschemas unterschiedliche Zeichenfolgen vorhanden sind, die gleich sortiert werden und hier Probleme verursachen würden¹.

Das ist ein sehr verbreiteter Trick (sieheInvertieren Sie die übereinstimmenden Zeilen, NUL-getrenntfür ein weiteres Beispiel mit comm), erfordert aber Dienstprogramme, die NUL in ihrer Eingabe unterstützen, was außerhalb von GNU-Systemen relativ selten ist.


¹ Beispiel:

$ touch dir1/{①,②} dir2/{②,③}
$ comm -12 <(cd dir1 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) \
           <(cd dir2 && find . -type f -print0 | tr '\n\0' '\0\n' | sort)  
./③
./②
$ (export LC_ALL=C
    comm -12 <(cd dir1 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) \
             <(cd dir2 && find . -type f -print0 | tr '\n\0' '\0\n' | sort))
./②

(2019 bearbeiten: Die relative Reihenfolge von ①②③ wurde in neueren Versionen der GNU libc korrigiert, aber Sie können

verwandte Informationen