plink bash -c 跳过第一个命令的参数

plink bash -c 跳过第一个命令的参数

当我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 运行三个命令:

  1. bash -c echo one
  2. echo two
  3. 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”。


为了避免此问题:

  1. 如果使用任何引用,请引用全部的命令也是如此。例如,如果您必须运行bash -c...,则应执行以下操作:

    plink -batch foo "bash -c 'echo one; echo two; echo three'"
    

    这样,里面的引号就会被保留。

  2. 为了简单起见,不要使用,bash -c除非你具体来说想要 bash。如果用户的标准 shell 没问题,只需直接发送命令 - 无论如何它都会运行$SHELL -c

    plink -batch foo 'echo one; echo two; echo three'
    

这同样适用于ssh以及plink

相关内容