【发布时间】:2021-05-05 18:18:02
【问题描述】:
在本地运行与通过 ssh 远程运行时,我得到以下不同的命令行为。
$ /bin/csh -c \'/bin/echo a b c d\'
Unmatched '''.
$ ssh node1 /bin/csh -c \'/bin/echo a b c d\'
a b c d
这里的 ssh 是否以不同的方式处理命令参数并以某种方式删除转义字符? (或者本地 shell 本身正在这样做?)
【问题讨论】:
在本地运行与通过 ssh 远程运行时,我得到以下不同的命令行为。
$ /bin/csh -c \'/bin/echo a b c d\'
Unmatched '''.
$ ssh node1 /bin/csh -c \'/bin/echo a b c d\'
a b c d
这里的 ssh 是否以不同的方式处理命令参数并以某种方式删除转义字符? (或者本地 shell 本身正在这样做?)
【问题讨论】:
TLDR:您的示例因本地 shell 处理而失败。
在 Unix 上,当进程 x(例如 shell)运行不同的程序 y(通常作为子进程,但不一定)时,它会将 y 自己的名称 加上任何参数作为 可变长度数组 字符串,例如在旧系统上echo a b c d 运行带有参数数组的echo 程序(为清楚起见,每行显示一个)
echo
a
b
c
d
(在最新系统echo 上的大多数shell 上是shell 内置而不是单独的程序,但其他 程序仍然以传统方式工作。)
因为 C 数组从下标 0 开始,并且参数数组通常命名为 argv(参数向量 - C 派生自 BCPL,其中数组称为向量)C(和 C++ 等)程序员通常将程序名称称为“argv -零”。请注意,您可以让同一个程序以多个名称出现在文件系统中,因此它的名称在编译时是未知的,只有在运行时才知道;这个技巧曾经在 gzip/gunzip 之类的东西上很流行,但近几十年来似乎已经过时了。
在 shell 输入中,反斜杠单引号意味着将该单引号视为普通数据,而不是用它来引用其他字符,例如分隔单词和参数的空格,所以
/bin/csh -c \'/bin/echo a b c d\'
使用以下 argv 运行 /bin/csh:
/bin/csh
-c
'/bin/echo
a
b
c
d'
csh(或 Bourne 类型的 shell)将 -c 之后的 one 参数作为要解析的整个命令 line(或脚本)和结果(可能) 已执行,但 '/bin/echo 不是有效的命令行。任何剩余的参数都不会被视为命令,而是可能的参数到正在运行的命令(如果需要它们)。
另一方面,ssh 客户端程序将任何和所有“数据”参数(不是选项,也不是必需的 [user@]remotehost 参数)视为构成要远程运行的命令,并通过 SSH 发送它们协议全部连接成一行,所以你的ssh 命令得到
ssh
node1
/bin/csh
-c
'/bin/echo
a
b
c
d'
但发送
/bin/csh -c '/bin/echo a b c d'
并且远程系统上的sshd 将整行作为一个参数传递给您的登录shell,然后将其作为一个单独的-c 参数,然后运行csh
/bin/csh
-c
/bin/echo a b c d
所以它将-c后面的一个参数作为命令行,它可以成功解析并运行。
而这种组合就是为什么我们在多个堆栈上有几十个 Q 用于“如何让 ssh 使用特殊字符和/或插值正确地远程运行此命令”的许多变体。虽然通常有一个可能的答案,但通常最简单的方法是通过运行不带远程命令参数的 ssh,因此它远程运行交互式 shell,并将所需的命令作为 输入 em> 到那个外壳;或者,几乎相同,将命令放入文件中,将该文件传输到远程系统(或通过 NFS 或类似方式访问),然后告诉远程系统运行 文件作为脚本。
【讨论】: