当使用IF语句时,如何将一个shell命令分成多行?

510

当命令是 if 语句的一部分时,我该如何在 shell 中将命令拆分成多行?

这样做有效:

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

我得到的不是整个命令执行的结果,而是:

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

更重要的是,我对Bash的理解中缺少什么,可以帮助我在未来理解这些问题及类似问题?


2
什么是错误?我能够执行 $ if ! cp -n log/server1.log \ .; then echo no copy; fi,没有错误,并在 \ 后换行。 - Miserable Variable
24
你的终端反斜杠\后面有空格吗?它们很难看到。如果有的话,你可能想要查看你的编辑器是否可以去除末尾空格或使其更加可见。 - msw
12
是的,终端反斜杠后面有空格。完全正确。谢谢。 - Dmitry Minkovsky
是的,抱歉,我应该发布“错误”(意外结果)!我的错!现在正在编辑。 - Dmitry Minkovsky
当其他人努力回答问题时,请考虑在代码片段中保留有问题的部分(斜杠后面的空格)。 - George Polevoy
显示剩余2条评论
2个回答

731

如果反斜杠和换行符之间有空格(空格或制表符¹),则换行符将失败。如果没有这样的空格,您的示例对我来说可以正常工作:

$ 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

以下是从评论中推出的一些细节:Shell中的行连续反斜杠不是真正的特殊情况; 它只是该通用规则的一个实例,其中反斜杠“引用”紧随其后的字符,防止其通常会受到的任何特殊处理。在这种情况下,下一个字符是换行符,被阻止的特殊处理是终止命令。通常,引用的字符最终包含在命令中; 反斜杠换行符被完全删除。但除此之外,机制是相同的。最重要的是,反斜杠仅引用紧随其后的字符;如果该字符是空格或制表符,则只会得到字面上的空格或制表符;对于随后的换行符,反斜杠将没有影响。

¹或回车符,就像Czechnology所指出的那样。 POSIX shell不能与Windows格式的文本文件配合使用,即使在WSL中也是如此。或Cygwin,但至少它们的Bash端口已经添加了一个igncr选项,您可以通过set -o激活它以使其容忍回车符。


6
马克,你知道吗,我一定有空格。只有在\后添加空格时,我才能重现错误。例如,当在第一个\后添加一个空格时,我会得到./soundops: line 73: --forward-agent: command not found。我的问题是我不理解这个错误。为什么有空格会导致该错误?空格+\n会"取消" \并分隔命令吗? - Dmitry Minkovsky
96
在换行符前面加上反斜杠可以防止换行符终止命令。但是,就像特殊的转义序列(如"\n")只能在反斜杠和n之间没有其他字符时起作用一样,反斜杠换行符也只有在反斜杠和换行符之间没有其他字符时才起作用。 - Mark Reed
25
哈哈哈,哇,当然有道理。从没想过这样。开了眼界,却又如此简单:它只是一个换行符。我讨厌看不见的字符。如果它们都是可见的,对我来说就更有意义了。谢谢! - Dmitry Minkovsky
7
大多数编辑器都可以让你显示那些看不见的字符。 - lucasvc
1
反斜杠和换行符从有效命令行中删除,但下一行的任何前导空格都会被保留。因此,它是否成为问题取决于单行命令中该点上的空格是否成为问题。 - Mark Reed
显示剩余3条评论

72

对于Windows / WSL / Cygwin等用户:

请确保您的行尾是标准的Unix换行符,即仅使用\n(LF)。

使用Windows行结尾的\r\n(CRLF)会破坏命令行断行。


这是因为在Windows行结尾处有\时,它会被转换为\ \r \n
正如Mark在上面正确解释的那样:

如果在反斜杠和换行符之间有空格,则行继续失败。

这不仅包括空格()或制表符(\t),还包括回车符(\r)。


2
这将解决在Windows中创建脚本,然后在Windows bash中使用它(例如bash -c MyShellScript.sh,其中MyShellScript.sh是在Windows编辑器中创建的)时创建的问题。您必须以UNIX格式保存MyShellScript.sh,可以使用notepad++来完成。 - BSalita
对于使用Notepad ++的用户,您可以在底部看到文件的行尾是什么。如果它读取Windows(CL CR),那么您应该将其更改为Unix(LF)。您可以单击它以进行更改。 - Javier Salas
1
非常感谢!您的回答在2020年甚至是巨大的帮助! - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接