为什么 ssh remote-server sh -c touch 1

为什么 ssh remote-server sh -c touch 1

目前获得

touch: missing file operand
Try `touch --help' for more information.

我跟着通过 ssh 执行 su -c找出我需要做的ssh remote-server 'sh -c "touch 1 && echo 2"'。但我想知道为什么……因为所有其他命令都正常工作,例如ssh remote-server echo -e 123

答案1

问题中打印的带有两层引号的命令应该可以正常工作。要调试此类问题,请使用“ssh -v”并查找“发送命令:”行以查看实际发送到远程主机的内容。例如:

$ ssh -v remotehost 2>&1 'sh -c "touch 1 && echo 2"' | grep command
debug1: Sending command: sh -c "touch 1 && echo 2"

当我去掉单引号时,我能够重现您的错误:

$ ssh  remotehost 2>&1 sh -c "touch 1 && echo 2" 
touch: missing file operand

使用上面显示的“ssh -v”进行调试,我们得到:

ssh -v remotehost 2>&1 sh -c "touch 1 && echo 2" | grep command
debug1: Sending command: sh -c touch 1 && echo 2

所以这里发生的是一个标准的 shell 引用问题。对于两层引号(上面的我的工作示例),它的解析方式如下:

你输入以下命令:

 ssh remotehost  'sh -c "touch 1 && echo 2"'

shell 将其解析为三个字符串:

string1:  ssh
string2:  remotehost
string3:  sh -c "touch 1 && echo 2"

然后,shell 找到“ssh”命令,并使用两个参数(上面的 string2 和 string3)运行它。

然后,“ssh”命令在远程主机上执行string3的内容,该内容被分解为3个字符串:

string1: sh
string2: -c
string3: touch 1 && echo 2

现在,该 shell 必须解析 string3。它将其分解为五个标记,并按预期进行解释。

如果没有双层引号,远程 shell 将尝试执行:

sh -c touch 1 && echo 2

如果您将其粘贴到本地命令行中,您将看到得到相同的结果。由于 shell 的命令行解析存在一些歧义,“1”被删除,尽管命令的其余部分按预期进行解析。如果您将“&&”更改为“||”(以便表达式的两边都得到执行),您将看到“2”仍然被打印出来。

这个故事的寓意是,您永远都不想让一个 shell 调用另一个 shell,因为您将陷入无尽的迷宫中,包括引用、反斜杠转义、变量扩展和解析歧义等问题,就像您在上面发现的那样。唉,通常没有办法避免这些构造,所以如果您必须这样做,请始终小心引用,并尽可能保持表达式简单。

相关内容