Hoe kan ik een shell-commando over meerdere regels splitsen bij gebruik van een IF-statement?

Hoe kan ik een commando splitsen over meerdere regels in de shell, als het commando deel uitmaakt van een if-statement?

Dit werkt:

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

Dit werkt niet:

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

In plaats van dat het hele commando wordt uitgevoerd, krijg ik:

./script.sh: line 73: --forward-agent: command not found

Wat nog belangrijker is, wat ontbreekt er aan mijn begrip van Bash dat me zal helpen dit en soortgelijke problemen in de toekomst te begrijpen?


Antwoord 1, autoriteit 100%

Het vervolg van de regel zal mislukken als u spaties (spaties of tabtekens¹) heeft na de backslash en vóór de nieuwe regel. Zonder zo’n witruimte werkt je voorbeeld prima voor mij:

$ 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

Enig detail gepromoot uit de opmerkingen: de backslash van de regel-voortzetting in de shell is niet echt een speciaal geval; het is gewoon een voorbeeld van de algemene regel dat een backslash het onmiddellijk volgende teken “citeert”, waardoor een speciale behandeling wordt voorkomen waaraan het normaal gesproken zou worden onderworpen. In dit geval is het volgende teken een nieuwe regel en de speciale behandeling die wordt voorkomen, is het beëindigen van de opdracht. Normaal gesproken komt een geciteerd karakter letterlijk in de opdracht te staan; een backslashed nieuwe regel wordt in plaats daarvan volledig verwijderd. Maar verder is het mechanisme hetzelfde. Het belangrijkste is dat de backslash alleen het onmiddellijk volgende teken citeert; als dat teken een spatie of tab is, krijg je gewoon een letterlijke spatie of tab; de backslash heeft geen effect op een volgende nieuwe regel.

¹ of wagenretouren, wat dat betreft, zoals Czechnology aangeeft. De POSIX-shell kan niet overweg met Windows-geformatteerde tekstbestanden, zelfs niet in WSL. Of Cygwin, maar hun Bash-poort heeft in ieder geval een igncr-optie toegevoegd die je kunt set -oom het wagenretourtolerant te maken.


Antwoord 2, autoriteit 10%

Voor gebruikers van Windows/WSL/Cygwin enz.:

Zorg ervoor dat uw regeleindes standaard Unix-regelfeeds zijn, d.w.z. alleen \n(LF).

Het gebruik van Windows-regeleinden \r\n(CRLF) regeleinden verbreekt de opdrachtregeleinde.


Dit komt omdat het hebben van \aan het einde van een regel met Windows-regeleinde zich vertaalt in
\\r\n.
Zoals Mark hierboven correct uitlegt:

De voortzetting van de regel zal mislukken als u witruimte heeft na de backslash en vóór de nieuwe regel.

Dit omvat niet alleen spatie () of tabs (\t), maar ook de regelterugloop (\r).

Other episodes