Ich möchte wiederholt etwas in einer Liste von Dateien tun. Die fraglichen Dateien haben Leerzeichen in ihren Namen:
david@david: ls -l
total 32
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha
-rw-rw-r-- 1 david david 0 Mai 8 11:55 haha~
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (3rd copy)
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (4th copy)
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (5th copy)
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (6th copy)
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (7th copy)
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (another copy)
-rw-rw-r-- 1 david david 13 Mai 8 11:55 haha (copy)
Jetzt möchte ich jede dieser Dateien statisieren:
david@david: echo '
for file in $(ls)
do
stat $file
done' | bash
(Ich benutze Echo und eine Pipe, um mehrzeilige Befehle zu schreiben.)
Wenn ich das mache, funktioniert es korrekt bei Dateien, deren Namen keine Leerzeichen enthalten. Aber die anderen ...
stat: cannot stat ‘(another’: No such file or directory
stat: cannot stat ‘copy)’: No such file or directory
Das Wechseln $(ls)
zu "$(ls)"
oder $file
zu "$file"
funktioniert nicht. Was kann ich machen?
Bearbeiten:
echo '
for files in *
do
stat "$files"
done' | bash
macht den Trick! Da ich neu in Bash bin, möchte ich die Dinge so einfach wie möglich halten - also nichts mit dem Versuch, Leerzeichen zu entkommen, oder mit xargs
oder der Lösung mit read -r
, obwohl sie das Problem lösen.
Wie einige gefragt haben: Ja, dies anstelle zu verwenden stat *
ist seltsam. Aber ich wollte nur einen allgemeinen Weg finden, um denselben Befehl mit einer for-Schleife auf eine Reihe von Dateinamen in bash anzuwenden. So stat
könnte stehen für gzip
, gpg
oder rm
.
quelle
stat *
? (;-)Antworten:
Das mehrfache Zitat aus dem
echo '
erschwert die Sache.Sie können einfach verwenden:
Aber auch
... und wenn Sie die Dateien sammeln und dann den Befehl anwenden möchten (warum?), können Sie fortfahren (aber seien Sie vorsichtig mit Dateien, die neue Zeilen enthalten ... (1))
... und wenn Sie auch versteckte Dateien möchten, verwenden Sie diese einfach
* .*
als Muster, aber denken Sie daran.
und..
sie werden im Set enthalten sein .Nebenbei sollten Sie die
ls
Ausgabe nicht analysieren .(1) aber wenn Sie Dateinamen mit Zeilenumbrüchen haben, haben Sie es etwas verdient ... ;-)
quelle
for f in *; do command "$f"; done
. Niemals analysierenls
, niemals in einerfor
Schleife ausführen und warum verwendenecho
?do
,|
,&&
etc, können Sie auf die neue Linie fortzusetzen. Entweder das oder Heredocs verwenden. Kein Grund zur Verwendungecho
und es kann auch Probleme verursachen.EnterNebenbei bemerkt: Sie können lange / komplizierte Befehle auf mehrere Zeilen aufteilen, indem Sie ein Leerzeichen gefolgt von einem Backslash hinzufügen und jedes Mal drücken , wenn Sie mit dem Schreiben in eine neue Zeile beginnen möchten, anstatt mehrere Prozesse mithilfe von zu forken
echo [...] | bash
. Außerdem sollten Sie$file
doppelte Anführungszeichen einfügen, um zu verhindern, dassstat
bei Dateinamen, die Leerzeichen enthalten, Fehler auftreten:Das Problem ist, dass es
$(ls)
zu einer Liste von Dateinamen mit Leerzeichen erweitert wird, und dasselbe passiert auch mit"$(ls)"
.Selbst wenn dieses Problem gelöst wird, wird diese Methode bei Dateinamen mit Backslashes und bei Dateinamen mit Zeilenumbrüchen (wie von terdon hervorgehoben) immer noch unterbrochen.
Eine Lösung für beide Probleme wäre, die Ausgabe von
find
an einewhile
Schleife weiterzuleiten, dieread -r
so ausgeführt wird, dass bei jeder Iterationread -r
einefind
Ausgabezeile gespeichert wird in$file
:quelle
ls
. Je.ls
einfach nicht . Es gibt bessere und robustere Wege. Vielleicht möchten Sie auch Folgendes lesen: Warum * nicht * `ls` analysieren? für mehr Details.ls
, es istfor
-for
iteriert über (IFS getrennte) Wörter, die nach demin
Schlüsselwort angegeben werden`for
undls
.for f in *
wäre zum Beispiel in Ordnung.Verwenden Sie das gute alte
find
, arbeitet mit versteckten Dateien, Zeilenumbrüchen und Leerzeichen.oder irgendein anderes statt
stat
quelle
Als R-Typ habe ich bereits eine Problemumgehung in R gefunden:
Ich weiß, es ist verrückt. Ich wünschte, die Ausgabe von
ls
wäre einfacher zu analysieren ... R kann mit Leerzeichen umgehen, da dir () einen Zeichenwert in Anführungszeichen zurückgibt. Alles zwischen den Anführungszeichen ist dann ein gültiger Dateiname mit Leerzeichen.quelle
for f in *
, drücken Sie die Eingabetaste und fahren Sie mit einer neuen Zeile fort :do
, drücken Sie erneut diestat "$f"
Eingabetaste, erneut diedone
Eingabetaste , geben Sie die Eingabetaste ein. Das ist ein Befehl, der gut in 4 Zeilen aufgeteilt ist und bei keinem Dateinamen kaputt geht.Ich bin auf andere Instanzen von Leerzeichenproblemen in for-Schleifen gestoßen, daher verwende ich im Allgemeinen den folgenden (imo robusteren) Befehl. Es passt auch gut in Rohre.
Sie können dies mit kombinieren
grep
oderfind
stattdessen verwenden:quelle
-E
Option hinzugrep
, ohne die sie+
in einem regulären Ausdruck nicht erkannt wird . Selbst dann ist es ein Swing und ein Miss bei dieser Frage, da Siegrep
Dateinamen mit Leerzeichen entfernen . Außerdem werden Dateinamen entfernt, die Ziffern (Ziffern) und Satzzeichen (z. B. Klammern) enthalten, wie dies in den Beispielen in der Frage der Fall ist. Dabei werden nicht einmal Dateinamen erwähnt, die Zeilenumbrüche enthalten oder mit-
(Bindestrich) beginnen.Diese Antwort löst das Problem des Parsens
ls
und kümmert sich um die Backspaces und neuen ZeilenVersuchen Sie dies, es wird Ihr Problem mit Internal Field Separator IFS lösen.
Aber Sie können es auch problemlos lösen, ohne die Ausgabe mit analysieren zu müssen
quelle
IFS
hier etwas ändern müssen : Das Zitieren der Variablen sollte ausreichen, um eine Wortaufteilung zu verhindern.ls
.Stattdessen können Sie Ihre Dateien umbenennen und das Leerzeichen durch ein anderes Zeichen wie Unterstrich ersetzen, um dieses Problem zu beheben:
Führen Sie dazu einfach den folgenden Befehl aus:
quelle