Vorgehensweise bei Ordnern/Dateien mit Leerzeichen bzw. Sonderzeichen
-
Hallo zusammen,
ich bin heute auf ein Problem gestoßen, welches sich einfach nicht lösen lässt. Auch Onkel Google hatte keine funktionierende Lösung parat oder ich hab es einfach nicht verstanden. Ich weiß einfach nicht mehr weiter.
Es geht um Leerzeichen bei Ordnern bzw. Dateinamen. Ich weiß, die sind natürlich böse. Aber 100% sicher kann man sich nie sein, weswegen ich am testen war, wie ich solche Strings einheitlich verpacke, damit z.B. eine Datei mit Leerzeichen erfolgreich von A nach B verschoben oder kopiert wird. Verschieben funktioniert, wie auch einige andere Dinge (mv, cat, cut, sed) wenn ich doppelte Hochkommata verwende.
Aber nachfolgenes Beispiel will nicht funktionieren:
cp -Rp '/test/test ordner 2/*' '/test/t t/' cp -Rp "/test/test ordner 2/*" "/test/t t/"
cp: cannot stat '/test/test ordner 2/*': No such file or directory
Das hier funktioniert wie erwartet:
cp -Rp /test/test\ ordner\ 2/* /test/t\ t/
Aber diese Lösung finde ich problematisch, weil ich hier separat ein bestimmtes Problem mit z.B. sed korrigieren würde. Aber was wäre bei anderen Sonderzeichen oder was es noch geben könnte? Hoher Aufwand, wenn es doch aus dem Bauch heraus auch einfacher gehen müsste.
Besser fänd ich da Hochkomata wie bisher, quasi "hey, das ist ein Parameter/String/Pfad und nicht Pfad Pfad Pfad....". Doch wie verklickere ich es den einzelnen Commandos möglichs einheitlich?
Falls relevant, ich arbeite unter VMware ESXi 5.0. Keine Ahnung welche Shell - hier funktioniet so gut wie garnichts - der Vim treibt mich auch noch in den Warnsinn (obwohl ich den gerne verwende)... aber es muss leider sein (Backups und so ohne externe Lösung).
Schöne Grüße
-
Das funktioniert auch:
cp -Rp '/test/test ordner 2/'* '/test/t t/'
Da steht das '*' ausserhalb der Hochkommata. Dadurch wird er von der shell interpretiert. In Hochkommata wird er eben nicht interpretiert. Eigentlich ist es ganz logisch, wenn man es ein mal verstanden hat.
Und wie kommt es, dass Du gerne vim verwendest, der Dich in den Wahnsinn treibt? Gefällt Dir der Wahnsinn
?
-
Ich versteh das Problem nicht so recht. Denn entweder hat man die Pfade hartkodiert und kann die Leerzeichen mit Backslash oder quotes manuell absichern oder man liest die Pfade von irgendwo, aber dann stehen die Pfade ja in Variablen, wo sich das Problem eh nicht stellt.
cp -- "$a" "$b"
funktioniert wunderbar, egal was für Sonderzeichen $a und $b auch enthalten mögen.
-
Ok, hier ein komplettes Beispiele. Das sollte mein Problem verständlich machen
/test # mkdir "test ordner 1" /test # mkdir "test ordner 2" /test # mkdir "test ordner 1/1" /test # mkdir "test ordner 1/2" /test # mkdir "test ordner 1/3" /test # touch "test ordner 1/a" /test # touch "test ordner 1/b" /test # touch "test ordner 1/c" /test # touch c /test # mv c "test ordner 1/" /test # /test # FROM="test ordner 1" /test # TO="test ordner 2" /test # cp -Rp "$FROM/*" "$TO" cp: cannot stat 'test ordner 1/*': No such file or directory /test #
War doch alles richtig? Es war in Hochkommata und sogar in Variablen. Ohne Hochkommata liefe es auf ein paar mehr Fehlermeldungen hinaus und letzteres macht keinen Unterschied.
Wenn ich die Leerzeichen jetzt mit einem Backslash maskiere (sed), dann funktioniet es perfekt (ob Variable oder nicht). Damit wäre das Problem gelößt. Danke so weit.
Jetzt stellt sich nur noch die Frage, ob das nur auf der Shell vom ESXi so ist (wobei es laut Google nicht nur bei VMware so zu sein scheint), sonst hätte ich gefragt, warum man die Leerzeichen nur bei ls, cp und grep maskieren muss und bei dirname, basename, cat, cut mkdir, rm, touch, source, sed, kill und chmod nicht. Diese Inkonsistenz regt mich ziemlich auf. Warum nicht einheitlich alles maskieren müssen?
Schöne Grüße
-
Achja, natürlich muss das so aussehen:
/test # cp -Rp test\ ordner\ 1/* test\ ordner\ 2
Denn so funktioniert es auch nicht:
/test # cp -Rp "test\ ordner\ 1/*" "test\ ordner\ 2" cp: cannot stat 'test\ ordner\ 1/*': No such file or directory
Problematisch scheinen also die Hochkommata zu sein. Gibt es zu diesen eine Alternative, welche das maskieren der Leerzeichen unnötig macht?
-
cp -Rp "$FROM"/* "$TO"
Oder gleich
rsync -a "$FROM"/ "$TO"
-
AnonFragesteller schrieb:
Problematisch scheinen also die Hochkommata zu sein. Gibt es zu diesen eine Alternative, welche das maskieren der Leerzeichen unnötig macht?
Wie oben schon beschrieben: Leerzeichen müssen nicht maskiert werden, wenn der Pfad in einer Variablen steht. Du kannst einfach direkt "$foo" schreiben, völlig egal, ob $foo Leerzeichen enthält oder nicht.
Leerzeichen escapen musst du nur, wenn du solche Pfade irgendwo hartkodierst.
-
Nennt mich hartnäckig, aber so schnell geb ich mich nicht geschlagen.
Dass hartkodiertes maskiert werden muss, wusste ich nicht und finde es gut, das zu jetzt wissen. Danke.Aber nützen tut das auch nichts. Hier ein Beispiel ohne hartcodierter Pfade & Co. Gleich vorweg: es funktioniert nicht.
#!/bin/sh ls -d * | while read ii do if [ ! -d $ii ]; then continue; fi mkdir $ii-2 cp -Rp $ii/* $ii-2/ done
Ergebnis:
/test # ll drwxr-xr-x 1 root root 512 Jun 1 07:55 test ordner 1 drwxr-xr-x 1 root root 512 Jun 1 08:52 test ordner 2 -rwxr-xr-x 1 root root 140 Jun 4 07:08 test.sh /test # ./test.sh sh: ordner: unknown operand cp: cannot stat '1/*': No such file or directory sh: ordner: unknown operand mkdir: cannot create directory 'test': File exists mkdir: cannot create directory 'ordner': File exists cp: cannot stat '2/*': No such file or directory /test # ll drwxr-xr-x 1 root root 512 Jun 1 07:55 test ordner 1 drwxr-xr-x 1 root root 512 Jun 1 08:52 test ordner 2 -rwxr-xr-x 1 root root 140 Jun 4 07:08 test.sh drwxr-xr-x 1 root root 512 Jun 4 07:12 test drwxr-xr-x 1 root root 512 Jun 4 07:12 ordner drwxr-xr-x 1 root root 512 Jun 4 07:12 2-2 drwxr-xr-x 1 root root 512 Jun 4 07:12 1-2 /test #
Und nun kommt wieder ihr
Btw. in meinem Script habe ich jetzt alle Änderungen wieder rückgängig gemacht. Denn nachdem ich alles habe automatisch maskieren lassen, verweigerten selbst Kommandos wie 'mv' den Dienst, welche zuvor sehr gut mit unmaskierten UND maskierten Leerzeichen klar kamen (Klartext & Variablen). Natürlich alles schön mit Echo ausgeben lassen und via C&P getestet. Von Hand kopiert und ausgeführt lief es plötzlich..... Liegt es vllt. nur an VMware ESXi 5? Ich weiß es nicht, aber eine Lösung muss es geben
Schöne Grüße,
AnonFragesteller
-
AnonFragesteller schrieb:
#!/bin/sh ls -d * | while read ii do if [ ! -d "$ii" ]; then continue; fi mkdir "$ii-2" cp -Rp "$ii"/* "$ii-2"/ done
Versuchs mal so.
Wobei ich mich frage, warum Du mit -d fragst, ob das ein Verzeichnis ist, wenn Du doch ls schon anweist, nur Verzeichnisse auszugeben.
Und denk daran, dass Du auch die Verzeichnisse '.' und '..' bekommst. Die könntest Du beispielsweise mit grep zwischen ls und while noch raus filtern.
-
Bei deinem Beispiel würde das passieren:
cp: cannot stat '[...]': No such file or directory
Ich frage danach noch mit -d ab, weil mir ls -d auch Dateien lieferte.
Ok, ich breche dann mal an dieser Stelle ab und bedanke mich für die Antworten
Das Backupscript läuft nun perfekt, so lange keine Leerzeichen im Spiel sind - auch nach einem Patch oder Neustart (auto. Reinstall des Script incl. GhettoVCB).Und was haben wir gelernt? Arbeite nie mit der ESXi Shell... oder dem ESXi vim -,-
-
Na siehst Du - mein Skript ist schon bis zum cp gekommen. Damit ist doch das eigentliche Problem gelöst. Also das Problem mit Leerzeichen. Das nächste Problem ist, dass Du ein leeres Verzeichnis hast. Da funktioniert das "foo/*" nicht, da es nichts zum expandieren gibt.
Und was lernen wir daraus: Man sollte in einer ruhigen Minute mal die man page der shell lesen.
Und überhaupt: was hat das ganze mit ESXi Shell oder gar vim zu tun
.
-
Welche manpages? Die gibt es beim ESXi nicht.
Und doch, in dem Ordner befanden sich Dateien.Wenn nicht nur ihr der Meinung seit, dass es eigentlich gehen müsste, es aber nicht geht, egal wie man es macht (siehe Beispiele von mir), dann läge der Verdacht nahe, dass es an der ESXi-Shell liegt.
Und was Vim angeht... nun, ich habe wärend meiner gesamten Ausbildung mit (g)Vim gearbeitet, auch Daheim - und die Variante vom ESXi ist einfach nur grausig.
Schöne Grüße,
AnonFragesteller
-
WICHTIGER LINK
Ich bin immer noch der Ansicht, dass das ein Job für rsync ist. Ansonsten sei angemerkt, dass
cp -RpT "$ii" "$ii-2"
macht, was du willst, ohne irgendwelche Expansionsprobleme zu haben. Das lässt sich mit anderen Tools kombinieren, etwa
find . -mindepth 1 -maxdepth 1 -type d -exec cp -RpT '{}' '{}-2' \;
um Verzeichisse herauszupicken.
So oder so musst du damit umgehen, dass du auf die Dauer Verzeichnisse der Form foo-2-2-2-2 bekommst, deren Inhalt nicht trivial vorhersagbar ist.