根据man ssh
和this previous answer,ssh应该传播它在远程服务器上运行的任何进程的退出状态。我似乎发现了一个神秘的异常!
$ ssh myserver exit 34 ; echo $?
34
好...
$ ssh myserver 'exit 34' ; echo $?
34
好...
$ ssh myserver bash -c 'exit 34' ; echo $?
0
什么?!?
$ ssh myserver
ubuntu@myserver $ bash -c 'exit 34' ; echo $?
34
因此问题似乎不是孤立的ssh或bash -c
,但它们的组合不能像我期望的那样工作。
我正在设计要在远程计算机上运行的脚本,该脚本需要采用在客户端计算的参数列表。为了论证,假设如果任何一个论据都不是远程服务器上的文件,则它失败:
ssh myserver bash -c '
for arg ; do
if [[ ! -f "$arg" ]] ; then
exit 1
fi
done
' arg1 arg2 ...
如何运行这样的内容并有效检查其退货状态?上面的测试似乎表明我不能。
答案 0 :(得分:3)
问题是报价丢失了。 ssh
只是连接参数,它不会重新引用它们,因此您实际上在服务器上执行的命令是:
bash -c exit 34
-c
选项仅接受一个参数,而不接受其余所有参数,因此它仅执行exit
; 34
被忽略。
如果这样做,您会看到类似的效果:
ssh myserver bash -c 'echo foo'
它将仅回显空白行,而不是foo
。
您可以通过为ssh
提供一个参数来解决此问题:
ssh myserver "bash -c 'exit 34'"
或加倍引号:
ssh myserver bash -c "'exit 34'"
答案 1 :(得分:1)
如果您的问题是如何在ssh的命令行中传递命令时远程运行命令,而又不会陷入触发有问题的错误的句柄中,则printf '%q '
可用于要求shell对命令进行引用代表您,构建一个字符串,然后将其传递给ssh:
printf -v cmd_str '%q ' bash -c '
for arg ; do
if [[ ! -f "$arg" ]] ; then
exit 1
fi
done
' arg1 arg2 ...
ssh "$host" "$cmd_str"
但是,只有在远程用户的默认外壳程序也是bash的情况下(或者,如果您在本地使用ksh的printf %q
,如果远程外壳程序是ksh,才能保证此方法正确运行) )。带外传递脚本文本要安全得多,就像在stdin上一样:
printf -v arg_str '%q ' arg1 arg2 ...
ssh "$host" "bash -s $arg_str" <<'EOF'
for arg; do
if [[ ! -f "$arg" ]]; then
exit 1
fi
done
EOF
...其中我们仍然依靠printf %q
来生成正确的输出,但仅用于参数,而不是脚本本身。
答案 2 :(得分:0)
尝试用引号引起来:
╰─➤ ssh server "bash -c 'exit 34' "; echo $?
34