eval 变量中的 ssh 命令

eval 变量中的 ssh 命令

我正在尝试通过ssh远程执行命令。但我将调用命令保存为变量,例如:

SSH_CMD="ssh -i path_to/identity"
SSH_USER=user
SSH_DST=server
dir1=dir1
dir2=dir2

现在如果我

eval $SSH_CMD $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

我收到错误(通常是mv: cannot stat 'dir1': No such file or directory:)

但如果我:

ssh -i path_to/identity $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

这样可行。所以问题似乎出在我的处理方式上eval。正确的方法是什么?

答案1

eval $SSH_CMD $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

这实际上与运行相同

eval "$SSH_CMD $SSH_USER@$SSH_DST mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

eval将它获取的参数连接到单个字符串,然后将其作为 shell 命令运行。特别是,&&作用在本地端,所以 shell 首先运行ssh ... mkdir dir1,如果成功,它运行mv dir1 dir2,等等,mkdir在远程主机上运行,​​但mv在本地主机上dir1不存在。


这里没有必要使用eval。你的第一个命令不需要它:

$SSH_CMD $SSH_USER@$SSH_DST "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

$SSH_CMD什么时候不是引用后,它会被分成三个单词ssh, -i, 和path_to/identity正如你想要的那样。这可行,但有点不干净,如果您必须在 中包含带有空格的参数$SSH_CMD,或者在那里使用全局字符,您会遇到麻烦。

如果您需要存储可变数量的命令参数(例如 in ) SSH_CMD,最好使用数组。另外,也引用其他变量以防止分词:

ssh_cmd=(ssh -i path_to/identity)
ssh_user=user
ssh_host=server
dir1=dir1
dir2=dir2
"${ssh_cmd[@]}" "$ssh_user@$ssh_host" "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

BashFAQ 050:我试图将命令放入变量中,但复杂的情况总是失败!我们如何运行存储在变量中的命令?更多细节。

答案2

我认为没有理由在这里使用eval,它只是在您的命令中引入了许多潜在漏洞。

您应该尽可能将选项存储在数组中,而不是像这样的变量:

SSH_OPTS=( -i path_to/identity )
SSH_USER=user
SSH_DST=server
dir1=dir1
dir2=dir2

那么你应该确保总是双引号你的变量:

ssh "${SSH_OPTS[@]}" "${SSH_USER}@${SSH_DST}" "mkdir $dir1 && mv $dir1 $dir2 && touch $dir2"

相关内容