nohup 与双与号 (&&) 而不是分号 (;) 一起使用时不起作用

Dan*_*rin 5 bash nohup

我有一个脚本,用于ssh登录远程机器、cd特定目录,然后启动守护程序。原始脚本如下所示:

ssh server "cd /tmp/path ; nohup java server 0</dev/null 1>server_stdout 2>server_stderr &"
Run Code Online (Sandbox Code Playgroud)

此脚本似乎工作正常。但是,对于用户输入错误路径导致cd失败的情况并不稳健。由于 ,即使失败;,此命令也会尝试运行该nohup命令cd

明显的修复不起作用:

ssh server "cd /tmp/path && nohup java server 0</dev/null 1>server_stdout 2>server_stderr &"
Run Code Online (Sandbox Code Playgroud)

也就是说,SSH 命令在服务器停止之前不会返回。放在nohup前面cd而不是前面java没有用。

谁能帮我解决这个问题?你能解释为什么这个解决方案不起作用吗?谢谢!

编辑: cbuckley 建议使用sh -c,我从中得出:

ssh server "nohup sh -c 'cd /tmp/path && java server 0</dev/null 1>master_stdout 2>master_stderr' 2>/dev/null 1>/dev/null &"
Run Code Online (Sandbox Code Playgroud)

但是,现在退出代码总是0cd失败时;而如果我这样做了,ssh server cd /failed/path我会得到一个真正的退出代码。建议?

Chr*_*lan 5

请参阅Bash 的运算符优先级

&被附加到整个语句,因为它具有比更高的优先级&&。您无需ssh验证这一点。只需在您的 shell 中运行它:

$ sleep 100 && echo yay &
[1] 19934
Run Code Online (Sandbox Code Playgroud)

如果&仅附加到echo yay,那么您的 shell 将休眠 100 秒,然后报告后台作业。但是,整个过程sleep 100 && echo yay都是后台运行的,您会立即收到工作通知。运行jobs将显示它挂出:

$ sleep 100 && echo yay &
[1] 20124
$ jobs
[1]+  Running                 sleep 100 && echo yay &
Run Code Online (Sandbox Code Playgroud)

您可以使用括号在 周围创建一个子shell echo yay &,为您提供您所期望的:

sleep 100 && ( echo yay & )
Run Code Online (Sandbox Code Playgroud)

这类似于使用bash -cto run echo yay &

sleep 100 && bash -c "echo yay &"
Run Code Online (Sandbox Code Playgroud)

把这些扔进一个ssh,我们得到:

# using parenthesis...
$ ssh localhost "cd / && (nohup sleep 100 >/dev/null </dev/null &)"
$ ps -ef | grep sleep
me 20136     1  0 16:48 ?        00:00:00 sleep 100

# and using `bash -c`
$ ssh localhost "cd / && bash -c 'nohup sleep 100 >/dev/null </dev/null &'"
$ ps -ef | grep sleep
me 20145     1  0 16:48 ?        00:00:00 sleep 100
Run Code Online (Sandbox Code Playgroud)

将此应用于您的命令,我们得到

ssh server "cd /tmp/path && (nohup java server 0</dev/null 1>server_stdout 2>server_stderr &)"
Run Code Online (Sandbox Code Playgroud)

或者:

ssh server "cd /tmp/path && bash -c 'nohup java server 0</dev/null 1>server_stdout 2>server_stderr &'"
Run Code Online (Sandbox Code Playgroud)

另外,关于您对帖子的评论,

对,sh -c总是返回 0。例如,sh -c exit 1有错误代码 0"

这是不正确的。直接从联机帮助页:

Bash 的退出状态是脚本中执行的最后一个命令的退出状态。如果没有执行任何命令,则退出状态为 0。

的确:

$ bash -c "true ; exit 1"
$ echo $?
1
$ bash -c "false ; exit 22"
$ echo $?
22
Run Code Online (Sandbox Code Playgroud)

  • 如果您只想覆盖优先级,可以使用 `{ cmd ; }` 而不是创建子shell。 (2认同)