Listen Sie Elemente mit Leerzeichen in zsh auf

10

Zu diesem Zeitpunkt habe ich 2 Stunden lang Zsh-Scripting studiert und bin gegen eine Wand gestoßen. Ich möchte eine Liste von Dateien durchgehen, die möglicherweise Leerzeichen enthalten. Ich bin offen für völlig andere Ansätze als das folgende Beispiel, solange sie zsh sind, da zsh das ist, was ich studiere, nicht die Aufgabe, die ich zu skripten versuche.

files=(`ls`)
for f in $files; do
    print $f
done

Ich erstelle natürlich nicht nur neu ls, ich möchte nur $fden gesamten Dateinamen bei jeder Iteration der Schleife erfassen.

Felix
quelle

Antworten:

12

Zunächst gehe ich davon aus, dass die Verwendung von lsnur ein Beispiel ist. Sie können die Ausgabe lsin keiner Shell analysieren , da sie nicht eindeutig ist. Lesen Sie, warum Sie die Ausgabe von ls (1) nicht analysieren sollten, wenn dies für Sie neu ist. Verwenden Sie in einer beliebigen Shell Platzhalter, um eine Liste der Dateien zu erhalten, z files=(*).

In zsh wird das Ergebnis der Befehlssubstitution wie in anderen Shells in Wörter mit Leerzeichen aufgeteilt (genauer gesagt entsprechend dem Wert von IFS). (Im Gegensatz zu anderen Shells unterliegt das Ergebnis der Befehlssubstitution nicht dem Globbing in zsh.) Wenn also die Ausgabe des lsBefehls lautet

hello world
wibble

files=($(ls))Legt dann fest , dass das filesArray 3 Elemente enthält : hello, worldund wibble.

Wenn die Befehlsersetzung in doppelte Anführungszeichen steht, wird keine Aufteilung durchgeführt. Sie können eine benutzerdefinierte Aufteilung mit Parametererweiterungsflags durchführen . Verwenden Sie das @Flag, um anzuzeigen, dass das Ergebnis der Aufteilung ein Array sein soll (seltsamerweise müssen Sie die Erweiterung in doppelte Anführungszeichen setzen, dh "${(@)…}"obwohl die Zeichenfolge in doppelten Anführungszeichen auf mehrere Wörter erweitert wird). Verwenden Sie zum Teilen das sFlag, z. B. "${(@s:,:)…}"um durch Kommas zu teilen. Die fFlagge wird nur bei Zeilenumbrüchen geteilt.

files=("${(@f)$(ls)}")

Beachten Sie, dass die richtige Methode zum Durchlaufen eines Arrays im Allgemeinen darin besteht for f in $files[@], $filesleere Elemente zu entfernen (hier spielt es keine Rolle, da die Elemente nicht leer sind).

print $fwird $fals Schalter interpretiert , wenn er mit a beginnt -und Backslashes in erweitert $f. Verwenden Sie print -r -- $foder, print -rn -- $fwenn Sie nach der Zeichenfolge keine neue Zeile hinzufügen möchten.

Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank. Ja, es war nur ein Beispiel. Im Moment gab es kein bestimmtes Ziel, ich möchte nur wissen, wie man die Listenelemente aus einem Befehl zitiert oder entzieht, der individuelle Ergebnisse mit Leerzeichen enthalten könnte.
Felix
Eine Sache, die ich verwirrend finde, ist, warum der äußere () in Ihren files = ("$ {(@ f) $ (ls)}") Ausdruck mit dem @f notwendig ist? Und nur herumspielen (f) scheint gut zu funktionieren, solange () außen erscheint.
Koobz
@Koobz 1. Die äußeren (…)sind notwendig, damit es sich filesum ein Array und nicht um eine Zeichenfolge handelt (die die Verkettung der Zeilen aus dem Befehl enthalten würde, wodurch die von vorgenommene Aufteilung rückgängig gemacht wird (f)). 2. Mit foo=$'one\n\nthree', contrast print -rl $ {(f) foo} `und print "${(@f)foo}". Die doppelten Anführungszeichen werden benötigt, um leere Zeilen beizubehalten, die Sie nicht erhalten, lsaber mit anderen Befehlen passieren können.
Gilles 'SO - hör auf böse zu sein'
Sehr geschätzt. Gibt es einen Reim oder Grund für diesen Wahnsinn? Selbst dort ist es verwirrend, warum die äußere () die Zeichenfolge nicht einfach wieder auf einzelne Wörter aufteilt, wenn der Zwischenwert meine verkettete Zeichenfolge ist. Dies sieht zum Beispiel wie eine String-Interpolation in Ruby oder PHP aus.
Koobz
@Koobz Der Grund für die besondere Behandlung leerer Wörter ist die historische Kompatibilität mit längst vergessenen älteren Versionen von zsh. Der Grund für die nicht automatische Aufteilung ist, dass es sich um ein überraschendes und oft nicht wünschenswertes Verhalten handelt. Die automatische Aufteilung ist ein Verhalten der Bourne-Shell, das zsh nur emuliert, wenn Sie es anweisen.
Gilles 'SO - hör auf böse zu sein'
2

In zsh können Sie die Erweiterung der Shell verwenden, die standardmäßig keine Wortteilung durchführt. Versuchen

for f in /path/to/files/*; do
    print ${f}
done
u-punkt
quelle