我有一个脚本使用ssh
登录到远程计算机,cd
到特定目录,然后启动一个守护程序。原始脚本如下所示:
ssh server "cd /tmp/path ; nohup java server 0</dev/null 1>server_stdout 2>server_stderr &"
此脚本似乎工作正常。但是,当用户输入错误的路径以致cd
失败时,它不健壮。由于;
,即使nohup
失败,此命令也会尝试运行cd
命令。
明显的修复不起作用:
ssh server "cd /tmp/path && nohup java server 0</dev/null 1>server_stdout 2>server_stderr &"
即,在服务器停止之前,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 &"
但是,当0
失败时,现在退出代码始终为cd
;而如果我ssh server cd /failed/path
,那么我会得到一个真正的退出代码。建议?
答案 0 :(得分:4)
请参阅Bash's Operator Precedence。
&
附加到整个语句,因为它的优先级高于&&
。您无需ssh
来验证这一点。只需在你的shell中运行它:
$ sleep 100 && echo yay &
[1] 19934
如果&
仅附加到echo yay
,那么您的shell将会休眠100秒,然后会报告后台作业。但是,整个sleep 100 && echo yay
都是背景资料,您会立即收到工作通知。正在运行jobs
会显示它已挂出:
$ sleep 100 && echo yay &
[1] 20124
$ jobs
[1]+ Running sleep 100 && echo yay &
您可以使用括号创建围绕echo yay &
的子shell,为您提供所期望的内容:
sleep 100 && ( echo yay & )
这类似于使用bash -c
来运行echo yay &
:
sleep 100 && bash -c "echo yay &"
将这些放入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
将此应用于您的命令,我们得到
ssh server "cd /tmp/path && (nohup java server 0</dev/null 1>server_stdout 2>server_stderr &)"
或:
ssh server "cd /tmp/path && bash -c 'nohup java server 0</dev/null 1>server_stdout 2>server_stderr &'"
另外,关于你对帖子的评论,
是的,
sh -c
始终返回0.例如,sh -c exit 1
有错误代码 0"
这是不正确的。直接来自联机帮助页:
Bash的退出状态是执行的最后一个命令的退出状态 剧本。如果未执行任何命令,则退出状态为0。
事实上:
$ bash -c "true ; exit 1"
$ echo $?
1
$ bash -c "false ; exit 22"
$ echo $?
22
答案 1 :(得分:1)
ssh服务器“test -d / tmp / path”&amp;&amp; ssh服务器“nohup ...&amp;”
答案 2 :(得分:0)
回答综述:
sh -c
包装整个nohup
命令不能用于我的目的,因为它不会返回错误代码。 (@cbuckley)ssh <server> <cmd1> && ssh <server> <cmd2>
有效,但速度慢得多(@ joachim-nilsson)<server>
上创建一个shell脚本,连续运行命令并返回正确的错误代码。最后一个是我最终使用的。我仍然有兴趣了解原始用例为什么不起作用,如果了解shell内部的人可以向我解释它!