bash &&运算符可以防止ssh上的背景

Hin*_*rik 7 ssh bash background-process

在试图弄清楚为什么Capistrano任务(试图在后台启动一个守护进程)挂起之后,我发现&&在bsh 中使用bsh会阻止后续程序在后台运行.我在bash 4.1.5和4.2.20上尝试过它.

以下将sleep在bash中挂起(即等待完成):

ssh localhost "cd /tmp && nohup sleep 10 >/dev/null 2>&1 &"
Run Code Online (Sandbox Code Playgroud)

以下不会:

ssh localhost "cd /tmp ; nohup sleep 10 >/dev/null 2>&1 &"
Run Code Online (Sandbox Code Playgroud)

这也不会:

cd /tmp && nohup sleep 10 >/dev/null 2>&1 &
Run Code Online (Sandbox Code Playgroud)

无论是什么情况,zsh和dash都会在后台执行它,无论是&&和ssh.这是bash或bug的正常/预期行为吗?

tor*_*rek 4

一种简单的解决方案是使用:

ssh localhost "(cd /tmp && nohup sleep 10) >/dev/null 2>&1 &"
Run Code Online (Sandbox Code Playgroud)

(如果您使用大括号,这也适用,请参见下面的第二个示例)。

我没有进一步进行实验,但我有理由相信这与闲置的打开文件描述符有关。也许 zsh 和 dash 绑定了,&&所以这意味着必须拼写为:

{ cd /tmp && nohup sleep 10; } >/dev/null 2>&1
Run Code Online (Sandbox Code Playgroud)

在bash中。


不,破折号中的快速实验表明,echo foo && echo bar >file仅重定向后者。尽管如此,它仍然与挥之不去的打开 fd 导致 ssh 等待更多输出有关;我过去经常遇到这种情况。
如果您在这种特殊情况下使用括号或大括号,则不需要另一个技巧,但在更一般的上下文中可能有用,其中要处理的命令集&&更复杂。&&由于 bash 似乎不恰当地使用而不是使用文件描述符;,因此您可以将a && b && c其变为a || exit 1; b || exit 1; c. 这适用于测试用例:

ssh localhost "true || exit 1; echo going on; nohup sleep 10 >/dev/null 2>&1 &"
Run Code Online (Sandbox Code Playgroud)

替换truefalse并省略“正在进行”的回显。

(您也可以set -e,尽管有时那是比预期更大的锤子。)