507 Stimmen

Wie kann ich ein Shell-Befehl über mehrere Zeilen aufteilen, wenn ich eine IF-Anweisung verwende?

Wie kann ich ein Kommando in der Shell über mehrere Zeilen aufteilen, wenn das Kommando Teil einer if-Anweisung ist?

Dies funktioniert:

if ! fab --fabfile=.deploy/fabfile.py --forward-agent --disable-known-hosts deploy:$target; then rc=1                                                                       
fi

Dies funktioniert nicht:

# funktioniert nicht:
if ! fab --fabfile=.deploy/fabfile.py \ 
  --forward-agent \
  --disable-known-hosts deploy:$target; then   
  rc=1
fi

Statt dass das gesamte Kommando ausgeführt wird, erhalte ich:

./script.sh: Zeile 73: --forward-agent: Befehl nicht gefunden

Was fehlt mir vor allem in meinem Verständnis von Bash, um dies und ähnliche Probleme in Zukunft zu verstehen?

729voto

Mark Reed Punkte 85468

Die Zeilenfortsetzung schlägt fehl, wenn Sie Leerzeichen (Leerzeichen oder Tabulatoren¹) hinter dem Backslash und vor dem Zeilenumbruch haben. Ohne solche Leerzeichen funktioniert Ihr Beispiel für mich einwandfrei:

$ cat test.sh
if ! fab --fabfile=.deploy/fabfile.py \
   --forward-agent \
   --disable-known-hosts deploy:$target; then
     echo failed
else
     echo succeeded
fi

$ alias fab=true; . ./test.sh
succeeded
$ alias fab=false; . ./test.sh
failed

Einige Details aus den Kommentaren hervorgehoben: Der Zeilenumbruch-Backslash in der Shell ist nicht wirklich ein spezieller Fall; es ist einfach eine Instanz der allgemeinen Regel, dass ein Backslash das unmittelbar folgende Zeichen "zitiert", was verhindert, dass es einer speziellen Behandlung unterzogen wird. In diesem Fall ist das nächste Zeichen ein Zeilenumbruch, und die spezielle Behandlung, die verhindert wird, besteht darin, dass der Befehl beendet wird. Normalerweise wird ein zitiertes Zeichen wörtlich in den Befehl aufgenommen; ein durch Backslash gekennzeichneter Zeilenumbruch wird stattdessen vollständig gelöscht. Aber sonst ist der Mechanismus derselbe. Am wichtigsten ist, dass der Backslash nur das unmittelbar folgende Zeichen zitiert; wenn dieses Zeichen ein Leerzeichen oder Tabulator ist, erhalten Sie einfach ein wörtliches Leerzeichen oder Tabulatoren; der Backslash hat keine Auswirkungen auf einen anschließenden Zeilenumbruch.

¹ oder Wagenrückläufe, wie Czechnology feststellt. Die POSIX-Shell verträgt sich nicht mit Windows-formatierten Textdateien, nicht einmal in WSL. Oder Cygwin, aber zumindest hat ihr Bash-Port eine igncr -Option hinzugefügt, die Sie mit set -o verwenden können, um sie gegen Wagenrücklässe toleranter zu machen.

71voto

Czechnology Punkte 14693

Für Windows/WSL/Cygwin etc. -Benutzer:

Stellen Sie sicher, dass Ihre Zeilenumbrüche Standard-Unix-Zeilenumbrüche sind, d.h. \n (LF) nur.

Die Verwendung von Windows-Zeilenumbrüchen \r\n (CRLF) wird den Befehlszeilenumbruch unterbrechen.


Dies liegt daran, dass das Vorhandensein von \ am Ende einer Zeile mit Windows-Zeilenumbruch zu \ \r \n wird.
Wie Mark oben korrekt erklärt:

Die Zeilenfortsetzung schlägt fehl, wenn Sie Leerzeichen nach dem Backslash und vor dem Zeilenumbruch haben.

Dies schließt nicht nur Leerzeichen () oder Tabs (\t) ein, sondern auch den Wagenrücklauf (\r).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X