How can I split a command over multiple lines in the shell, when the command is part of an if
statement?
This works:
if ! fab --fabfile=.deploy/fabfile.py --forward-agent --disable-known-hosts deploy:$target; then rc=1
fi
This doesn't work:
# does not work:
if ! fab --fabfile=.deploy/fabfile.py \
--forward-agent \
--disable-known-hosts deploy:$target; then
rc=1
fi
Instead of the whole command executing, I get:
./script.sh: line 73: --forward-agent: command not found
More importantly, what is missing from my understanding of Bash that will help me understand this and similar issues in the future?
The line-continuation will fail if you have whitespace (spaces or tab characters[1]) after the backslash and before the newline. With no such whitespace, your example works fine for me:
$ 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
Some detail promoted from the comments: the line-continuation backslash in the shell is not really a special case; it is simply an instance of the general rule that a backslash "quotes" the immediately-following character, preventing any special treatment it would normally be subject to. In this case, the next character is a newline, and the special treatment being prevented is terminating the command. Normally, a quoted character winds up included literally in the command; a backslashed newline is instead deleted entirely. But otherwise, the mechanism is the same. Most importantly, the backslash only quotes the immediately-following character; if that character is a space or tab, you just get a literal space or tab, and any subsequent newline remains unquoted.
[1] or carriage returns, for that matter, as Czechnology points out. Bash does not get along with Windows-formatted text files, not even in WSL. Or Cygwin, but at least their Bash port has added a set -o igncr
option that you can set to make it carriage-return-tolerant.