Wie leite ich eine Liste mit für Menschen lesbaren Pfaden auf einen anderen Befehl um?

Wie leite ich eine Liste mit für Menschen lesbaren Pfaden auf einen anderen Befehl um?

Wenn Sie mit der Ausgabe von Befehlen arbeiten, die beispielsweise locatePfadlisten in „für Menschen lesbarer Form“ (also ohne \Leerzeichen vorn) erzeugen, wie leiten Sie deren Ausgabe auf einen anderen Befehl um?

Die Ausgabe von $ locate [something]erzeugt Pfade mit Leerzeichen, was andere Programme daran hindert, die Pfade zu verwenden, wenn sie Leerzeichen enthalten. Wenn ich zum Beispiel

$ du -h `locate *.doc`

dies erzeugt einen Fehler bei allen Dateien und Verzeichnissen, die Leerzeichen enthalten. (das Einschließen der Häkchen in Leerzeichen funktioniert nicht)

Antwort1

Aus welchem ​​konkreten Grund verwenden Sie locate? Dies scheint das zu tun, wonach Sie gefragt haben:

find . -type f -name '*doc' -exec du -h "{}" \;

Das heißt, wenn SieWirklichlocateWenn Sie ein Tool wie oder verwenden und dessen Eingabe als Parameter an ein anderes Programm übergeben möchten, können Sie die durch Trennzeichen getrennte Ausgabe und Eingabe findnutzen, die einige Tools bieten. Beide haben eine Option ( 's und 's ), die Ihnen eine programmierfreundlichere Ausgabe ermöglicht, die zum Lesen mitNULlocatefindlocate-0find-print0xargses ist -0Streit:

find . -type f -name '*doc' -print0 | xargs -0 du -h

locate -0 '*doc' | xargs -0 du -h

Antwort2

Wenn Sie die gleiche Zeile an mehrere Befehle übergeben möchten/müssen, würde etwa Folgendes funktionieren:

#!/usr/bin/env bash

T="${IFS}" # Save off the Internal Field Separator

IFS=$'\n' # Set it to newline.

while read file_line
do
        echo "--"
        echo "${file_line}"
        echo "--"
done <<< $(locate $1) 
IFS="${T}  # Set it back to the original IFS. 

Es ist eine gute Idee, zu wickelnbeliebigVariablen, die möglicherweise Leerzeichen in "" enthalten.

Antwort3

Wenn Befehlsersetzungen ( $(...)oder die `...`veraltete Form) ohne Anführungszeichen gelassen werden, wird in Bourne-ähnlichen Shells split+glob (split nur in zsh) aufgerufen.

Die Aufteilung erfolgt $IFSstandardmäßig für Zeichen des Sonderparameters, der Leerzeichen, Tabulatoren und Zeilenumbrüche (und NUL in zsh) enthält. Dies erklärt, warum Ihr Befehl bei Dateinamen, die Leerzeichen enthalten, nicht funktioniert.

Du könntest es tun:

(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))

Aber das würde immer noch fehlschlagen, wenn Dateinamen Zeilenumbruchzeichen enthalten. Die Ausgabe locateist einfach nicht nachbearbeitbar.

Die meisten locateImplementierungen bieten die -0Möglichkeit, die Dateipfade NULdurch -Trennzeichen auszugeben. NUL ist der einzige Bytewert, der in einem Dateipfad nicht vorkommen kann. Das bedeutet, dass die Ausgabe nachbearbeitbar ist. Sie müssen nur bei NULs aufteilen.

In zsh:

IFS=$'\0'
du -hc -- $(locate -0 '*.doc')

Oder besser noch, mit einem expliziten Split-on-NUL-Operator:

du -hc -- ${(0)"$(locate -0 '*.doc')"}

In bash4.4+ könnte das sein:

readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"

Damit bleiben noch zwei Probleme bestehen:

  1. Wenn locatekeine Datei gefunden wird, du -hc --wird es ohne Argumente ausgeführt, was bedeutet, dass Sie die Datenträgernutzung des aktuellen Arbeitsverzeichnisses erhalten.
  2. Wenn andererseits locateviele Dateien gefunden werden, kann es passieren, dass Sie ein Limit für den execve()Systemaufruf erreichen und eineArgumentliste zu langFehler.

Beide Probleme können wie folgt vermieden werden:

locate -0 '*.doc' | xargs -r0 du -hc --

( -rund -0sind nicht standardmäßige Erweiterungen der GNU-Implementierung von, xargswie z. B. -heine nicht standardmäßige Erweiterung der GNU-Implementierung von du).

Dies führt jedoch zu einem neuen Problem: Es wird mehrmals xargsausgeführt, um das Limit zu umgehen. Dies bedeutet jedoch, dass Sie mehrere Zeilen erhalten und auch die Datenträgernutzung für eine Datei, die mehrmals fest verknüpft ist, möglicherweise mehrmals gezählt wird.duexecve()total

Dank wird es nicht ausgeführt, wenn -rkeine Datei gefunden wird. Das bedeutet aber auch, dass Sie keine Zeile erhalten.dulocate0 total

Mit neueren Versionen von GNU dukönnen diese Probleme wie folgt behoben werden:

locate -0 '*.doc' | du --files0-from=- -hc

Dieses Mal wird die Dateiliste über eine Pipe statt über Argumente übergeben, sodass es keine Größenbeschränkung für Argumente gibt. Das bedeutet auch, dass keine großen Speichermengen für die Speicherung dieser Liste reserviert werden müssen und die duArbeit daran beginnen kann, sobald locatemit der Ausgabe begonnen wird.

verwandte Informationen