Emma2
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Vorab: Ich habe ein bisschen ein schlechtes Gewissen, für eine Mini-Frage einen weiteren Thread aufzumachen, aber das scheint ja richtig so zu sein? Problem: Mein Skript übernimmt mehrere Parameter, von denen mindestens einer ein Pfad ist und Leerzeichen enthalten kann. Im Laufe des Skripts will ich feststellen, ob das so bezeichnete Directory leer ist oder nicht, Ich mache dies mit dem Befehl ls -A und zwar per
| #!/bin/bash
if ! [ `ls -A "$2/$1.bak"` ]
then
echo "$2/$1.bak: Verzeichnis ist leer!"
fi
echo Ende!
|
Das funktioniert jedoch nicht für beliebige Verzeichnisnamen, konkret passiert dieses:
| $ ./syntaxttests.sh "Ding 2" "/home/ralfp/Knack 2.bak"
/home/ralfp/Knack 2.bak/Ding 2.bak: Verzeichnis ist leer!
Ende!
$ ./syntaxttests.sh "vmMintXfce" "/home/ralfp/VirtualBox VMs/Linux-Tests"
./syntaxttests.sh: Zeile 3: [: Zu viele Argumente.
/home/ralfp/VirtualBox VMs/Linux-Tests/vmMintXfce.bak: Verzeichnis ist leer!
Ende!
|
Was macht im zweiten Aufruf die Probleme? Für mich sehen die doch gleichwertig aus... bis auf das Minuszeichen? (BTW: Das Verzeichnis ist nicht leer.)
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7651
|
Da müsstest du dann noch `` in "" setzen. statt `` besser $() und ein -z davor weil sonst kann das immer noch schiefgehen wenn der Verzeichnisname eine Sonderbedeutung hat Was bei ls auch passieren kann, also besser ls -A -- "$x" ls ist generell ne schlechte Idee
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Nun bin ich vollends verwirrt: Warum funktioniert mein erster Aufruf und der zweite nicht? Liegt es tatsächlich am Minuszeichen? frostschutz schrieb: statt `` besser $()
Das Ergebnis bleibt das Gleiche. Trotz Quellcode
| if ! [ $(ls -A "$2/$1.bak") ]
|
wird es
| $ ./syntaxttests.sh "Ding 2" "/home/ralfp/Knack 2.bak"
/home/ralfp/Knack 2.bak/Ding 2.bak: Verzeichnis ist leer!
Ende!
$ ./syntaxttests.sh "vmMintXfce" "/home/ralfp/VirtualBox VMs/Linux-Tests"
./syntaxttests.sh: Zeile 3: [: Zu viele Argumente.
/home/ralfp/VirtualBox VMs/Linux-Tests/vmMintXfce.bak: Verzeichnis ist leer!
Ende!
|
frostschutz schrieb: ls ist generell ne schlechte Idee
Ich bin sehr offen für eine bessere Idee: Wie kann ich (in einem if) feststellen, ob ein Verzeichnis leer ist? (Hintergrund: Ich arbeite am Backup und will das alte Backup nur löschen, wenn die neue nicht-leer ist, andernfalls habe ich nach zweimaligem Scheitern gar kein Backup mehr.)
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
frostschutz schrieb: Da müsstest du dann noch `` in "" setzen.
statt `` besser $()
Nö, das hilft leider auch nicht. Der Code
| if ! [ $(`ls -A "$2/$1.bak"`) ]
|
generiert nun
| $ ./syntaxttests.sh "Ding 2" "/home/ralfp/Knack 2.bak"
/home/ralfp/Knack 2.bak/Ding 2.bak: Verzeichnis ist leer!
Ende!
$ ./syntaxttests.sh "vmMintXfce" "/home/ralfp/VirtualBox VMs/Linux-Tests"
./syntaxttests.sh: Zeile 3: laaaaaaaaaaaaaaaang: Befehl nicht gefunden
/home/ralfp/VirtualBox VMs/Linux-Tests/vmMintXfce.bak: Verzeichnis ist leer!
Ende!
|
(wobei "laaaaaaaaaaaaaaaang" ein Element im Test-Verzeichnis ist). frostschutz schrieb: und ein -z davor weil sonst kann das immer noch schiefgehen wenn der Verzeichnisname eine Sonderbedeutung hat
ändert nichts. ... und wenn ich die Backquotes wegnehme
| if [ -z $(ls -A "$2/$1.bak") ]
|
gelingt der erste Aufruf immer noch, aber der zweite geht auch immer noch schief:
| $ ./syntaxttests.sh "Ding 2" "/home/ralfp/Knack 2.bak"
/home/ralfp/Knack 2.bak/Ding 2.bak: Verzeichnis ist leer!
Ende!
$ ./syntaxttests.sh "vmMintXfce" "/home/ralfp/VirtualBox VMs/Linux-Tests"
./syntaxttests.sh: Zeile 3: [: Zu viele Argumente.
Ende!
|
Irgendwo habe ich da doch einen Wurm drin... einen Unverständniswurm. ☹ Ich sehe echt nur noch das Minuszeichen als Unterschied. Aber kann es das sein?
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7651
|
| [ -z "`dings`" ]
# oder
[ -z "$(dings)" ]
# oder auch -n statt -z , je nachdem
|
alternativ auch mal mit shellcheck experimentieren
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Oh, Menno...
frostschutz schrieb:
Dann bin ich jetzt bei
| if [ -z "$(ls -A "$2/$1.bak")" ]
|
. und das scheint zu funktionieren. Danke! Aber wie ist das nun zu lesen?
Die Anführungszeichen um die Parameter sorgen dafür, dass ls funktioniert, das $() "klammert" den Aufruf (Kommandosubstitution?), und die äußeren Anführungszeichen machen wieder einen String daraus? So ungefähr?
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17548
Wohnort: Berlin
|
Als Faustregel gilt: Niemals die Ausgabe von ls parsen! Das führt nur zu Schusswunden im Knie. Insbesondere die ganzen Maskierungsprobleme sind ein nie endender Quell von Unbill. Der help test -Aufruf bringt es an den Tag:
| -d FILE True if file is a directory.
-e FILE True if file exists.
-f FILE True if file exists and is a regular file.
|
| verz=$2
file=$1
test -d "$verz" && test -f "$verz/$file".bak && echo Backupfile existiert || echo Kein Verzeichnis oder geuschter Backupfile nicht im Verzeichnis
|
Semantisch ist es auch falsch, zu behaupten, dass ein Verzeichnis leer sei, nur weil eine bestimmte Datei nicht drin ist.
| mkdir d e
touch d/foo.bak
for verz in {d..f}; do for file in {foo,bar}; do
test -d "$verz" && test -f "$verz/$file".bak && echo Backupfile "$verz/$file.bak" existiert || echo Kein Verzeichnis "$verz" oder geuschter Backupfile "$file.bak" nicht im Verzeichnis
done ; done
Backupfile d/foo.bak existiert
Kein Verzeichnis d oder geuschter Backupfile bar.bak nicht im Verzeichnis
Kein Verzeichnis e oder geuschter Backupfile foo.bak nicht im Verzeichnis
Kein Verzeichnis e oder geuschter Backupfile bar.bak nicht im Verzeichnis
Kein Verzeichnis f oder geuschter Backupfile foo.bak nicht im Verzeichnis
Kein Verzeichnis f oder geuschter Backupfile bar.bak nicht im Verzeichnis
|
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Äh... prinzipiell hast Du Recht (was die Semantik angeht), aber $2/$1.bak ist ein Verzeichnis. (Hintergrund: Das Verzeichnis meiner Maschine heißt $2/$1, und das kopiere (mit rsync) ich lokal nach $2/$1.bak, um die VM möglichst schnell wieder hochzufahren; erst danach rsync-e ich das übers Netz weg. Ich weiß also prinzipiell nicht, welche Dateien in dem Verzeichnis sein sollten, aber wenn es leer ist, ist die lokale Kopie fehlgeschlagen, und dann brauche ich den rsync übers Netz ja gar nicht zu machen.) Aber wie könnte ich das mit test denn machen, wenn ich keinen Namen kenne? Ich finde keine passende Option.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17548
Wohnort: Berlin
|
Gilt dann als nichtleer, auch wenn nur Unterverzeichnisse drin sind.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
user_unknown schrieb:
Der Ansatz ist problematisch: | $ mkdir foo
$ touch foo/a foo/b
$ find foo
foo
foo/a
foo/b
$ verz=foo
$ test -e $verz/*
bash: test: foo/a: binary operator expected
$ echo $?
2
|
user_unknown schrieb: Als Faustregel gilt: Niemals die Ausgabe von ls parsen! Das führt nur zu Schusswunden im Knie.
Trifft auch gerne mal den Fuß. 😉
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17548
Wohnort: Berlin
|
rklm schrieb: user_unknown schrieb:
Der Ansatz ist problematisch: | $ mkdir foo
$ touch foo/a foo/b
$ find foo
foo
foo/a
foo/b
$ verz=foo
$ test -e $verz/*
bash: test: foo/a: binary operator expected
$ echo $?
2
|
user_unknown schrieb: Als Faustregel gilt: Niemals die Ausgabe von ls parsen! Das führt nur zu Schusswunden im Knie.
Trifft auch gerne mal den Fuß. 😉
Oh, Du hast Recht*). Hast Du auch eine Lösung oder empfiehlst Du dann doch die Ausgabe von ls zu parsen? Vielleicht mit find -not -empty : | res=$(find $verz -type d -name $file -not -empty)
|
*) Bzw. auch wieder nicht, weil zu diplomatisch. Der Ansatz ist nicht problematisch, sondern falsch.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
user_unknown schrieb: rklm schrieb: user_unknown schrieb:
Der Ansatz ist problematisch:
Hast Du auch eine Lösung oder empfiehlst Du dann doch die Ausgabe von ls zu parsen?
Man kann das z.B. so machen: | unset found
for f in $verz/*; do
found=yes
break
done
if [ -n "$found" ]; then
...
fi
|
Aber: ich würde einfach den rsync reparieren - der muss ja auch mit einem leeren Verzeichnis funktionieren. Und man kann ja auch ein leeres Verzeichnis nach remote kopieren - da passiert ja nicht viel. Mir fehlt leider gerade die Zeit, nach dem Fehler zu suchen.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
rklm schrieb:
Man kann das z.B. so machen: | unset found
for f in $verz/*; do
found=yes
break
done
|
Da ist ein Fehler, denn die Schleife wird normalerweise auch einmal durchlaufen, wenn es keinen Fund gibt. Richtig ist mit "nullglob" in der bash oder so, wie es mit allen Bourne-Shells funktioniert: | unset found
for f in $verz/*; do
[ -e "$f" ] && found=yes && break
done
|
|