Frage von Melonenbowle, 49

bash Script: Leerzeichen- und Variablen-Auswertungsproblem?

Hallo!

( tl;dr ? überflieg das Fettgedruckte und das CodeBeispiel =) )

Das Problem ist etwas komplexer, ich konnte es aber auf das folgende, einfache Problem begrenzen:

  • Prüfe ob das Verzeichnis /backups/01 today/ existiert.
  • falls Ja: Wechsle in das Verzeichnis und dann führe den Befehl macheX aus
  • ansonsten: gib eine Fehlermeldung aus

Kern des Problems: Das Verzeichnis enthält enthält ein Leerzeichen und der Pfad muss vor dem Prozess in der Variablen DIRR gepeichert werden. (Der Pfad kann nicht umbenannt werden, das wäre zu einfach)

Ich habe in etwa folgendes:

#!/bin/bash

DIRR="/backups/01 today"

if [ -d $DIRR ];
then
  cd $DIRR
  macheX
else
   echo "FEHLER: $DIRR existiert nicht!"
fi

Wie man sieht wird die Variable DIRR anfangs gesetzt und wird anschließend auf drei unterschiedliche arten ausgewertet. Ich habe im Code-Beispiel bewusst auf ` ' und " Einfassungen von DIRR verzichtet, denn genau das ist das Problem! Wie müssen diese DIRR eingefasst werden und wie der Pfad angegeben werden, damit es funktioniert?

Ich habe etliche Kombinationen durch und werde langsam verrückt. =) Wenn ich den Pfad z.B. mit oder ohne escape-Zeichen vor dem Leerzeichen angebe, dann klappt das eine aber es hakt dann wieder wo anders. In der Fehlermeldung darf das Verzeichnis beliebig erscheinen (mit ` ' " oder auch dem escape-Zeichen \ )

Wer schafft es mein Brett vorm Kopf zu zersägen? =)

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von xxtesaxx, 14

Okay, hier noch mal eine etwas ausführlichere Erläuterung, über die "Hilfreiche Antwort" würd ich mich freuen weil ich noch ziemlich neu bei Gute Frage bin und bisher noch keine hab :P

Wenn du einen Pfad in einer Variable speichern willst, macht es erst einmal keinen Unterschied ob du " oder ' verwendest. Beide Zeilen schreiben deinen Pfad in die Variable. Die dritte Variante ist das Escapen des Whitespaces:

DIR_A="this/is/my path"
DIR_B='this/is/also valid'
DIR_C=this/is/my\ third\ option

Mittels einem einfachen "echo $DIR_A, $DIR_B, $DIR_C" wirst du feststellen, dass alle Pfade wie erwartet ausgegeben werden

Interessant wird es jetzt, wenn du die Variable an ein anderes Programm übergeben willst. In deinem Fall heißt das Programm "cd" was für change directory steht. Studiert man die Bedienungsanleitung des Programms wird man herausfinden, dass das erste Argument ein Pfad sein muss, in welches das Programm wechseln soll.

Jetzt muss man natürlich wissen, dass Argumente in Bash per Leerzeichen getrennt werden. Außerdem können viele Programme noch Optionen erhalten, welche meist mit einem "-" (Minus) übergeben werden.

Bei cd sieht es dann z. B. so aus: "cd /path/to/directory". Du willst aber den Pfad deiner Variablen nutzen, also versuchen wir es mit "cd $DIR_A". Nun sagen wir Bash, dass wir den Wert in DIR_A einsetzen wollen. Dies geschieht durch die verwendung des $ (Dollar) Zeichens.

Im Hintergrund passiert nun folgendes: Aus "cd $DIR_A" wird "cd this/is/my path". Du siehst, cd erhält 2 Argumente ("this/is/my" und "path"). Um das zu verhindern müssen wir Bash deshalb sagen, dass der Wert in $DIR_A als ein einzelner String verwendet werden muss.

Dazu benutzen wir die doppelten Anführungszeichen ("). Warum nicht einzelne Hochkommas? Nun, diese escapen den Wert. Wie darf man das verstehen? Nun, hier ein Beispiel:

cd "$DIR_A"; pwd

Wechselt in das Verzeichnis und gibt es anschließend auf der Konsole aus während 

cd '$DIR_A'; pwd

Dir eine Fehlermeldung mit dem Inhalt "$DIR_A: no such file or directory" geben wird. Anschließend wird der Pfad des aktuellen Directories ausgegeben.

Nun ist noch die Frage, was is mit dem Backticks (`) auf sich hat. Nun, diese können genutzt werden um einen Befehl auszuführen. Hier ein Beispiel:

DIR_D=`pwd`/another/path\ example

Diese Zeile führt pwd (Ausgabe des akteullen Pfades) im aktuellen Verzeichnis aus und hängt anschließend "/another/path example" an den Pfad dran.

Soo, ich hoffe das schafft nun genügend Klarheit :)

Kommentar von Melonenbowle ,

Gerade wegen der Erläuterung zu den "AuswertungsUnterschieden" der verschiedenen Anführungszeichen, ist dieser Beitrag, auch für andere ähnliche Probleme, am hilfreichsten - ich selbst habe etwas herum experimentiert und die Unterschiede nun endgültig begriffen. Es ist so einfach (wenn man erst mal weiß was man da überhaupt macht =) ) Danke!

Antwort
von xxtesaxx, 30

Folgender Code funktioniert bei mir (OS X El Capitan):

#!/bin/bash
DIRR='./test/te st'
if [ -d "$DIRR" ];
then
cd "$DIRR"
echo "Laeuft bei mir!" else
echo "FEHLER: $DIRR existiert nicht!"
fi

Zu beachten ist, dass du den Pfad in DIRR in Hochkommas setzt. Du kannst auch gar keine Zeichen um den Pfad setzen. Dann musst du aber den Whitespace mit \ escapen.

Der Trick ist nun $DIRR in Anführungszeichen (") zu setzen.

Warum ist das so? Nun $DIRR enthält zwar deinen Pfad und dieser ist auch korrekt, allerdings übergibst du deine Variable an das Programm "cd". Dieses nutzt den ersten Parameter den es übergeben bekommt als Pfad. Parameter trennt es per Whitespace. Um dem Programm also klar zu machen, dass der komplette Pfad der Parameter ist, muss er in Anführungszeichen gesetzt werden. Wenns dir geholfen hat würd ich mich über "Hilfreiche Antwort"-Markierung freuen :)

Kommentar von Melonenbowle ,

Danke! Es läuft! Und wieder etwas schlauer! Made my day! und das will was heissen um 7 =D

Kommentar von xxtesaxx ,

Ich sitz in Australien, hier ist es 6 Stunden später ^^ Kannst du die Antwort noch als Hilfreich markieren? :)

Kommentar von guenterhalt ,

Ich sitz in Australien, hier ist es 6 Stunden später ^^ Kannst du die Antwort noch als Hilfreich markieren? :)

nein das geht nicht. Du hast den Fehler begangen, gleich eine richtige Antwort zu geben. Hilfreichste bedeutet, dass es gleichzeitig auch noch weniger hilfreiche Antworten geben muss. Bei nur einer Antwort scheidet das nun mal aus.

Es gibt aber doch 3 Möglichkeiten:
1. du schreibst eine 2. Antwort (das prüft gutefrage.net nicht)
2. der Fragende schreibt sich selbst eine Antwort (auch das lässt gutefrage.net zu)
3. irgendjemand erbarmt sich und schreibt etwas, was gutefrage.net nicht löscht.

Kommentar von Melonenbowle ,

Nachtrag, weil ich ja wirklich verstehen will: ich hab ' und "
verwechselt, das war mein Fehler. Da nützte dann alles zusätzliche
hantieren mit \ natürlich nix. Aber gut so, aus Fehlern lernt man am
besten. Der Unterschied zw. ` ' und " ist auch wirklich nicht so leicht
zu verstehen für Anfänger. Obwohl ich in der Programmierung wahrhaft nicht unbedarft bin, nur bash ist Neuland, ein schönes Land und voller Goldgruben =)


PS: Aber klar! Thumbs up! Den Stern gibt's sobald es geht!

Expertenantwort
von guenterhalt, Community-Experte für Linux, 14

einen funktionierenden Hinweis hat dir @xxtesaxx gegeben.

Das nur als 3. Möglichkeit ( siehe meinen Kommentar ).

Kommentar von Melonenbowle ,

Huhu! Das ist ja wieder was. Ist man mal ne Weile weg ist wieder alles anders =) Danke für die Info! - Ich rechne es dem GF-Team aber hoch an, dass sie dafür sorgen das es gepflegter zugeht! Also, auch wenn es keinen Stern geben mag, erbarmt sich vielleicht der/die dies lesende GF-Mitarbeiter/in xxtesaxx's Antwort zu Kennzeichnen, weil diese hilfreich, richtig und ausführlich ist und bestimmt noch anderen helfen wird =)

Expertenantwort
von guenterhalt, Community-Experte für Linux, 3

Der Pfad kann nicht umbenannt werden, das wäre zu einfach

so etwas umgehe ich einfach mit einem symbolischen Link

cd /backups/

ln -s "01 today" 01today

damit hast du das Original-Verzeichnis nicht umbenann, kannst aber doch den gleichen Namen aber ohne Leerzeichen verwenden.

Keine passende Antwort gefunden?

Fragen Sie die Community

Weitere Fragen mit Antworten