是否可以在远程 ssh 命令中使用变量?

Posted

技术标签:

【中文标题】是否可以在远程 ssh 命令中使用变量?【英文标题】:is it possible to use variables in remote ssh command? 【发布时间】:2013-02-21 06:48:35 【问题描述】:

我想在远程机器上依次执行几个命令,后面的一些命令依赖于前面的命令。在最简单的例子中,我得到了这个:

ssh my_server "echo this is my_server; abc=2;"
this is my_server
abc=2: Command not found.
ssh my_server "echo this is my_server; abc=2; echo abc is $abc"
abc: undefined variable

对于一些背景信息,我真正想做的是拼凑一条路径并启动一个 java 应用程序:

ssh my_server 'nohup sh -c "( ( echo this is my_server; jabref_exe=`which jabref`; jabref_dir=`dirname $jabref_exe`; java -jar $jabref_dir/../jabref.jar` $1 &/dev/null ) & )"' &
jabref_dir: Undefined variable.

这样,每当 jabref 在服务器上更新为新版本时,我就不必手动更新 jar 文件的路径。 jabref 可执行文件不带参数,但使用 java -jar 启动它可以,这就是为什么我必须稍微调整一下路径。

目前我有一个单独的脚本文件中的命令列表并调用

ssh my_server 'nohup sh -c "( ( my_script.sh &/dev/null ) & )"' &

这可行,但由于 ssh 调用已经在一个脚本文件中,所以将所有内容放在一起会很好。

【问题讨论】:

【参考方案1】:

在这个例子中

ssh my_server "echo this is my_server; abc=2;"

abc 设置在远程端,所以应该清楚为什么它没有设置在本地机器上。

在下一个例子中,

ssh my_server "echo this is my_server; abc=2; echo abc is $abc"

您的本地 shell 在将参数发送到远程主机之前尝试扩展参数中的 $abc。稍作修改就会如您所愿:

ssh my_server 'echo this is my_server; abc=2; echo abc is $abc'

单引号会阻止您的本地 shell 尝试扩展 $abc,因此文字文本会将其发送到远程主机。


要最终解决你真正的问题,试试这个:

jabref_dir=$( ssh my_server 'jabref_exe=$(which jabref); jabref_dir=$(dirname $jabref_exe);
               java -jar $jabref_dir/../jabref.jar > /dev/null; echo $jabref_dir' )

这将在远程服务器上将引用的字符串作为命令运行,并仅输出一个字符串:$jabref_dir。该字符串被捕获并存储在本地主机上的变量中。

【讨论】:

谢谢,这让我走上了正轨。防止通过逗号或\$ 扩展是关键。事实证明,服务器上的默认 shell 是 tcsh,这也是 abc=2 不起作用的另一个原因。 很好的答案。我正在使用 Jenkins 和 SSH 代理插件,它就像一个魅力。 惊人的答案。就像@craq 说在 $ 前面放一个 \ 是关键并立即修复它。【参考方案2】:

在 chepner 的一些启发下,我现在有了一个可行的解决方案,但仅在从 bash shell 或 bash 脚本调用时才有效。它不适用于 tcsh。

ssh my_server "bash -c 'echo this is \$HOSTNAME; abc=2; echo abc is \$abc;'"

基于此,下面的代码是一个在远程服务器上运行 jabref 的本地脚本(尽管默认情况下使用 X 转发和无密码身份验证,用户无法判断它是远程的):

#!/bin/bash
if [ -f "$1" ]
then
    fname_start=$(echo $1:0:4)
    if [ "$fname_start" = "/tmp" ]
    then
        scp $1 my_server:$1
        ssh my_server "bash -c 'source load_module jdk; source load_module jabref; java_exe=\$(which java); jabref_exe=\$(which jabref); jabref_dir=\$(echo \$jabref_exe%/bin/jabref);eval \$(java -jar \$jabref_dir/jabref.jar $1)'" &
    else
        echo input argument must be a file in /tmp.
else
    echo this function requires 1 argument
fi

这是 1 行脚本 load_module,因为 modulecmd 设置了环境变量,如果不使用脚本,我无法弄清楚如何做到这一点。

eval `/path/to/modulecmd bash load $1`;

我还查看了 heredocs,其灵感来自 How to use SSH to run a shell script on a remote machine? 和 http://tldp.org/LDP/abs/html/here-docs.html。好的部分是它甚至可以从 tcsh 工作。我从命令行得到了这个工作,但不是在脚本中。这可能很容易解决,但我现在有一个解决方案,所以我很高兴:-)

ssh my_server 'bash -s' << EOF
echo this is \$HOSTNAME; abc=2; echo abc is \$abc;
EOF

【讨论】:

以上是关于是否可以在远程 ssh 命令中使用变量?的主要内容,如果未能解决你的问题,请参考以下文章

在远程 ssh 命令中传递变量

ssh远程连接服务器执行命令

为啥 SSH 远程命令在手动运行时获得的环境变量更少? [关闭]

利用shell脚本执行ssh远程另一台主机执行命令并返回命令的结果集

解决SSH远程执行命令找不到环境变量的问题

ssh如何远程执行命令?