当我plink
与结合时bash -c
,第一个命令没有接收参数。
命令:
plink -batch myuser@myhost bash -c 'echo one; echo two; echo three'
实际产量
<empty line>
two
three
预期输出
one
two
three
知道发生了什么事吗?(解决方法很明确:只需添加不带参数的 echo;但我更想寻找这种奇怪行为的根本原因)
答案1
SSH 服务器接收的完整命令行是不是作为单独的参数传递,就像您在 Unix-ish 环境中所期望的那样 - 它始终作为单个字符串进行传输,然后传递给sh -c
(使用用户选择的“登录 shell”)。
对于“plink”和“ssh”客户端,客户端命令行中指定的多个参数只需用空格连接在一起,不保留原始引用(因为客户端实际上并不知道远程 shell 需要什么样的引用语法)。因此您的命令:
plink -batch foo bash -c 'echo one; echo two; echo three'
实际上相当于:
plink -batch foo 'bash -c echo one; echo two; echo three'
因为三个参数bash
、-c
、 和echo one; echo two; echo three
被连接成一个字符串,无需任何其他处理。
因为该命令已经通过shell执行,所以在服务器端实际运行的是:
$SHELL -c 'bash -c echo one; echo two; echo three'
用户的登录 shell 运行三个命令:
bash -c echo one
echo two
echo three
请注意,第一个命令是不是 bash -c 'echo one'
。因为原来的引述早已遗失,所以现在这是两个独立的论点。
在该命令中,只有单词echo
是赋予的实际命令参数-c
,而后面的单词one
不是——而是位置参数。如果没有-c
,bash 会期望该位置有一个脚本文件名,但如果有,-c
它只是一个任意字符串,成为的值$0
。例如:
bash -c 'echo 0=$0, 1=$1, 2=$2' one two three
因此,在您的情况下发生的情况是,bash 将单词“one”分配给 $0,然后运行不带任何参数的“echo”。
为了避免此问题:
如果使用任何引用,请引用全部的命令也是如此。例如,如果您必须运行
bash -c...
,则应执行以下操作:plink -batch foo "bash -c 'echo one; echo two; echo three'"
这样,里面的引号就会被保留。
为了简单起见,不要使用,
bash -c
除非你具体来说想要 bash。如果用户的标准 shell 没问题,只需直接发送命令 - 无论如何它都会运行$SHELL -c
:plink -batch foo 'echo one; echo two; echo three'
这同样适用于ssh
以及plink
。