目前获得
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,因为您将陷入无尽的迷宫中,包括引用、反斜杠转义、变量扩展和解析歧义等问题,就像您在上面发现的那样。唉,通常没有办法避免这些构造,所以如果您必须这样做,请始终小心引用,并尽可能保持表达式简单。