我想使用 ssh 从各种服务器捕获一些数据并在某些条件下运行一些命令。
我不想这样做:
if ssh $host test -f /file; then
# If file exists
var=$(ssh $host long pipeline)
else
# if it doesn't
var=$(ssh $host another long pipeline)
fi
因为它会使过程更长。我想在远程机器上执行 if else 。
我尝试了几种方法,但我没有运气。
var=$(ssh $host if [ -f /file ]\; then long pipeline1 \; else long pipeline2 \; fi)
基于这个答案,它可以工作,但 pipeline1 的最后一个命令假定它else
和 pipeline2 的其余部分作为它的参数。
command: can't read else: No such file or directory
...
command: can't read fi: No such file or directory
然后我尝试了这个
var=$(ssh $host test -f /file \&\& pipeline1 \|\| pipeline2)
同样, pipeline1 的最后一个命令被||
视为其参数。
我也在下面尝试过(基于this),它正在工作:
do_this () {
if [ -f /file ]; then
pipeline1
else
pipeline2
fi
}
var=$(ssh $host "$(set); do_this")
然而,它会打印不影响我的变量的不需要的错误消息,但它对我的脚本来说很难看。
bash: line 1: BASHOPTS: readonly variable
bash: line 8: BASH_VERSINFO: readonly variable
bash: line 24: EUID: readonly variable
bash: line 71: PPID: readonly variable
bash: line 82: SHELLOPTS: readonly variable
bash: line 92: UID: readonly variable
有什么建议么?
更新
我想我必须包括我的管道是什么,基本上它只是一堆文本处理:
cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
根据Jetchisel的回答,简而言之,我必须用单引号括起我的命令。
var=$(ssh $host 'if [ -f /file ]; then cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-' ; else cat otherfile | ... ; fi'
我得到了tr: invalid option -- ';'
。tr
当作;
它的论据。
它使用heredoc
:
var=$(ssh $host <<-EOF
if [ -f file ]; then
pipeline1
else
pipeline2
fi
EOF
)
然而,由于我在 sed 中使用的正则表达式,它破坏了 vim 的着色。我现在会接受heredoc
作为答案。
更新 2:我相信我的问题不是sshpass 中的多个命令的重复,我的情况更具体,而另一个线程一般会问它。
在:
ssh
实际上运行一个 shell(目标用户的登录 shell)来解释您作为参数传递的代码。如果给出了多个参数,ssh 将它们与空格连接起来,并再次让用户的登录 shellhost
解释它。通常,您希望将单个代码参数传递给并确保它用单
ssh
引号引起来,以确保本地 shell 不会进行扩展。如果您知道远程用户的登录 shell 类似于 Bourne/POSIX,那么您所要做的就是:
如果要远程解释的代码必须在其中包含单引号,则需要将它们插入为
'\''
(保留单引号,插入带引号的(带反斜杠)单引号,重新输入单引号)。如果您不能保证远程用户的外壳,并且您不需要通过其标准输入将数据传递给远程命令(并且没有远程命令从其标准输入读取,除非它重定向到其他东西比 ssh 连接),您可以改为:
通过引用第一个
EOF
,我们确保本地 shell 没有在 here 文档中进行扩展。我们显式调用sh
以解释其标准输入上的代码,因此我们知道编写脚本的语法。这种方法还避免了必须转义单引号。
您的
可以写成:
所以这给了我们:
(如果远程用户的登录 shell 是例如 csh、tcsh、fish、rc、es、akanga,其语法与 Bourne/POSIX-like 语法不同,这将不起作用)
或者:
几年前我做了类似的事情,这就是我的做法。
首先测试退出状态。
检查退出状态。
输出是
127
因为没有/etc/fstabs
但/etc/fstab
现在更改
/etc/fstabs
以/etc/fstab
注意没有尾随s
再次检查退出状态
输出是
0
因为/etc/fstab
在远程机器中有。然后只需将其放入变量中并检查退出状态并根据它执行您的脚本。也将退出状态保存在变量中。
这就是我在那种情况下幸存下来的方式,我并不是说这是一个完美的解决方案,但你可以检查一下。顺便说一句,我将 ssh 密钥转发到远程主机,因此当我通过 ssh 登录时没有密码检查。我还在两台机器上都使用 bash 作为登录 shell,这就是为什么我
exec bash -li
最后有