[solved] Bash for Schleife für Dateien mit whitespaces
-
Hallo,
sorry ich habe leider keine passendere Kategorie gefunden. Ich habe das Problem, dass ich ein Tool schreiben möchte, dass in einem Ordner die Dateien so benennt wie der Parent-Ordner + fortlaufende Nummer. Das mit dem Parent Ordner habe ich hinbekommen, aber es hapert bei den Dateinamen mit Whitespaces. Hier mal mein aktuelles Skript:
#funktioniert pdir=`basename \`readlink -e "$1"/..\`` # Whitespaces werden escaped, aber for checkt das nicht for f in `ls -b "$1"`; do thefile="$1/$f" if [[ -f "$thefile" ]]; then # rename ... fi done
Ich habe zu diesem Problem immer Varianten mit "find" gesehen, aber ich würde es trotzdem so gerne wissen. Muss doch irgendwie gehen. Gibt es denn Ansätze, wie ich generell kompatibel zu allen Dateinamen arbeiten kann. Funktioniert diese Variante mit "$1" denn für alle $1 oder kann man auch ein " mitgeben und somit jedes Tool crashen?
Vielen Dank für Antworten
-
PhilippHToner schrieb:
# Whitespaces werden escaped, aber for checkt das nicht for f in `ls -b "$1"`; do
Da hast du was falsch verstanden.
Mit `` wird eine subshell erzeugt und dieser das kommando
ls -b "$1" übergeben.
for erhält nur das ergebnis des kommandos.
-
Das habe ich soweit schon verstanden und `ls -b` liefert alle Inhalte, wobei durch -b die Whitespaces escaped werden. for in iteriert durch alle Token, die mit Whitespace getrennt ist. Somit verstehe ich eigentlich nicht, warum es nicht funktioniert. Aber okay, wenn es nicht geht, wie löse ich es dann, wenn ich selber die Schleife bauen möchte?
-
for f in $1; do ... done
Das funktioniert auch mit Dateien mit Whitespace.
-
Alles klar vielen Dank. War ja wieder klar, dass die einfachste Lösung die Richtige ist
-
tntnet schrieb:
for f in $1; do ... done
Das funktioniert auch mit Dateien mit Whitespace.
also wenn in $1 der Verzeichnisname steht, macht der Code nicht was er soll.
So könnte es gehen:
for f in "$1"/*; do ...
Der Schleifenrumpf muss dazu auch angepasst werden weil hier in $f schon "dir/name" steht.
-
Das ist eine ziemlich schlechte Lösung. Was ist mit Dotfiles?
Sowas löst man normalerweise mit man: find(1), der OP wollte sowas nur zum Üben manuell zusammenbasteln, wenn ich das richtig verstanden habe.
-
nman schrieb:
Das ist eine ziemlich schlechte Lösung. Was ist mit Dotfiles?
Sowas löst man normalerweise mit man: find(1), der OP wollte sowas nur zum Üben manuell zusammenbasteln, wenn ich das richtig verstanden habe.
Warum ist das eine ziemlich schlechte Lösung (welche eigentlich)? Es ist eine Lösung für eine Aufgabe. Nicht für alle Aufgaben. Dotfiles, also Dateien, die mit einem Punkt anfangen, sind per Konvention nicht sichtbar. Und dann kommt es auf die Aufgabe an, ob ich alle Dateien oder nur die sichtbaren verarbeiten möchte.
man: find(1) ist ganz nett. Das ist eine Lösung für viele Aufgaben. Aber auch das hat seine Nachteile. Für manche Aufgaben ist find nicht notwendig und macht das Skript dadurch weniger gut lesbar und damit weniger wartbar.
Wenn ich dann mit den Dateien, die
find
liefert etwas anfangen möchte, dann habe ich die Wahl zwischen-exec
undxargs
.Xargs kann wie auch
find
in der GNU-Variante Dateien mit Hilfe des Nullterminators auch mit Leerzeichen verarbeiten. Allerdings muss das Kommando eine Liste von Dateinamen am Ende erwarten.-exec
hat den Nachteil, dass es zum einen syntaktisch nicht so lesbar ist und zum anderen wird für jede gefundene Datei ein Prozess gestartet. Das kann bei vielen Dateien eine große Systemlast erzeugen.
-
Ich sprach vom letzten Beitrag (von Eipothead). Deine Lösung ist genau das, wonach der OP gefragt hatte und für Übungszwecke (und einige andere Fälle) auch vollkommen ok. Die jetzt aber für Realworld-Zeugs (das sich von der ursprünglichen Fragestellung unterscheidet) adaptieren zu wollen, halte ich nicht für sehr klug.
-
nman schrieb:
Ich sprach vom letzten Beitrag (von Eipothead). Deine Lösung ist genau das, wonach der OP gefragt hatte ...
aber die "Lösung" macht doch gar nicht das richtige
$ a=/tmp $ for i in $a; do echo $i; done /tmp