
Wenn Sie mit der Ausgabe von Befehlen arbeiten, die beispielsweise locate
Pfadlisten 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 SieWirklichlocate
Wenn 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 find
nutzen, die einige Tools bieten. Beide haben eine Option ( 's und 's ), die Ihnen eine programmierfreundlichere Ausgabe ermöglicht, die zum Lesen mitNUL
locate
find
locate
-0
find
-print0
xargs
es ist -0
Streit:
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 $IFS
standardmäß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 locate
ist einfach nicht nachbearbeitbar.
Die meisten locate
Implementierungen bieten die -0
Möglichkeit, die Dateipfade NUL
durch -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 bash
4.4+ könnte das sein:
readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"
Damit bleiben noch zwei Probleme bestehen:
- Wenn
locate
keine Datei gefunden wird,du -hc --
wird es ohne Argumente ausgeführt, was bedeutet, dass Sie die Datenträgernutzung des aktuellen Arbeitsverzeichnisses erhalten. - Wenn andererseits
locate
viele Dateien gefunden werden, kann es passieren, dass Sie ein Limit für denexecve()
Systemaufruf erreichen und eineArgumentliste zu langFehler.
Beide Probleme können wie folgt vermieden werden:
locate -0 '*.doc' | xargs -r0 du -hc --
( -r
und -0
sind nicht standardmäßige Erweiterungen der GNU-Implementierung von, xargs
wie z. B. -h
eine nicht standardmäßige Erweiterung der GNU-Implementierung von du
).
Dies führt jedoch zu einem neuen Problem: Es wird mehrmals xargs
ausgefü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.du
execve()
total
Dank wird es nicht ausgeführt, wenn -r
keine Datei gefunden wird. Das bedeutet aber auch, dass Sie keine Zeile erhalten.du
locate
0 total
Mit neueren Versionen von GNU du
kö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 du
Arbeit daran beginnen kann, sobald locate
mit der Ausgabe begonnen wird.