我需要对以下代码进行一些解释,因为它们是相同的概念,但工作原理不同。因此,我正在尝试执行以下操作:
#!/bin/sh
ssh -T username@host << EOF
relative="$HOME/Documents"
command=$(find \$relative -name GitHub)
command2=$(echo \$relative)
echo "HERE: \$command"
echo "HERE: \$command2"
EOF
这是我得到的输出:
find: ‘$relative’: No such file or directory
HERE:
HERE: /home/username/Documents
我尝试了以下方法:
"\$relative"
'\$relative'
"\${relative}"
"\$(relative)"
答案 0 :(得分:3)
您大部分步骤都做对了,但是忘记了here-doc item.ModuleName
中的命令替换构造。不这样做将使命令在本地外壳而不是远程主机中扩展。
另外,在运行$(..)
命令时,转义的find
会将文字字符串传递给它不理解的\$relative
命令,即在本地计算机上发生以下情况
find
因此,您需要转义整个命令替换结构,以将整个here-doc扩展移动到远程主机中。
find \$relative
# ^^^^ since $relative won't expand, find throws an error
或者完全使用heredocs的替代形式,允许您不解释heredoc文本中的变量。只需将定界标识符引用为ssh -T username@host << EOF
relative="\$HOME/Documents"
command=\$(find "\$relative" -name GitHub)
command2=\$(echo "\$relative")
echo "HERE: \$command"
echo "HERE: \$command2"
EOF
'EOF'
答案 1 :(得分:2)
这里文档的内容被解析两次;一次是通过本地外壳程序,然后是远程外壳程序(通过ssh连接发送之后)。这两种解析的工作方式不同:第二种(远程)按常规shell规则播放,而第一种(本地)仅 则查看反斜杠,$
表达式(例如变量和命令替换) )和反引号样式的命令替换。最重要的是,本地的根本不关注引号,因此,将诸如单引号引起来的内容对它的解析方式(直到到达远端)没有影响。
例如,在以下行中:
relative="$HOME/Documents"
$HOME
在本地计算机上扩展到本地用户的主目录路径。我很确定您希望它在远程计算机上扩展到远程用户的主目录路径。为此,您必须转义$
:
relative="\$HOME/Documents"
下一行比较复杂:
command=$(find \$relative -name GitHub)
在这里,第二个$
被转义了(通常会保留它以便在远端进行解释),但第一个不是。这意味着整个$(find \$relative -name GitHub)
命令替换都在本地计算机上运行。如果您运行:
find \$relative -name GitHub
...作为常规命令,您会得到错误“查找:‘$ relative’:没有这样的文件或目录”,因为转义可防止变量替换的发生。加上它在错误的计算机上。因此,再次需要转义$
(顺便说一句,您还应该对变量引用加双引号):
command=\$(find "\$relative" -name GitHub)
下一行也有类似的问题,但是排序仍然成功。
无论如何,这里有两种可能的解决方案:要么在here文档中转义$
个字符的 all ,要么在文档定界符周围加上引号,然后再转义它们中的任何一个都是因为这会跳过所有本地分析(查找结尾定界符除外):
#!/bin/sh
ssh -T username@host << 'EOF'
relative="$HOME/Documents"
command=$(find "$relative" -name GitHub)
command2=$(echo "$relative")
echo "HERE: $command"
echo "HERE: $command2"
EOF
如果您不希望在本地计算机上扩展任何内容,则此方法更简单。