我让 SSH 在脚本中执行一些命令,如下所示:
#!/bin/bash
REMOTEUSER=$1
REMOTEHOST=$2
newVh=$3
ssh "$REMOTEUSER"@"$REMOTEHOST" << EOF
cd
if [ ! -d "/data/web/someDirectory" ]
then
echo -e "There is no vhost setup for someDirectory"
exit 1
fi
if [ ! -d "git" ]
then
echo -e "Home git directory not found. Creating it now."
mkdir git
fi
if [ ! -d "git/$newVh.git" ]
then
echo -e "Bare git repository not found for $new. Creating it now."
mkdir git/"$newVh".git
git init --bare git/"$newVh".git
fi
EOF
效果很好并且可以满足我的要求。我正在尝试检查compass
远程计算机上是否安装了 ruby gem,如果没有,我想安装它。我将这一行添加到脚本的底部:
.
.
.
if [ `gem list compass -i` == 'false' ]
then
echo -e "Compass not installed... Installing it now."
gem install compass -V
fi
EOF
但`gem list compass -i`
。事先在我的本地计算机上进行评估(我安装了指南针)。即使在不带引号的脚本中运行gem list compass -i
以查看输出也会返回,true
这是不正确的。我尝试用多个\
s 转义该命令,但没有成功。
我猜有两个问题:
为什么脚本中的其他命令(mkdir
、等...)在远程计算机上可以正常工作,但cd
不能?git init
gem list
如何转义该命令以远程运行它?
答案1
原始代码的问题在于命令替换表达式(由反引号表示)在执行命令之前进行评估ssh
。在不同的情况下,您可能会考虑引用here-doc关键字(例如“EOF”),以防止here-doc中的参数扩展,但在这种情况下,您实际上确实希望在客户端执行一些参数替换。因此,这里的解决方案可能是逃避命令替换。试试这个:
if [ \`gem list compass -i\` == 'false' ]
then
echo -e "Compass not installed... Installing it now."
gem install compass -V
fi
转义的反引号会阻止评估命令替换。
我还要提到的是,用于命令替换的反引号语法被广泛认为是一个遗留功能,而美元符号语法现在通常是首选。下面是上面的代码片段使用美元符号语法的样子:
if [ \$(gem list compass -i) == 'false' ]
then
echo -e "Compass not installed... Installing it now."
gem install compass -V
fi
有关这两种表示法之间差异的更多信息,您可以参考以下 StackExchange 帖子:
您可能还想查看有关命令替换的 GNU Bash 手册页。
并且还在有关重定向的 GNU Bash 手册页。
请特别注意此处文档中的以下小节:
3.6.6 此处文档
这种类型的重定向指示 shell 从当前源读取输入,直到一行仅包含单词(没有尾随空白)可见。到该点读取的所有行都将用作标准输入(或文件描述符n如果n被指定)为一个命令。
这里文档的格式是:
[n]<<[-]word here-document delimiter
不执行参数和变量扩展、命令替换、算术扩展或文件名扩展单词。如果任何部分单词被引用,则分隔符是删除引号的结果单词,并且此处文档中的行未展开。如果单词不加引号,here-document 的所有行都经过参数扩展、命令替换和算术扩展,字符序列 \newline 被忽略,并且必须使用 '\' 来引用字符 '\'、'$'、和“”。
如果重定向运算符是“<<-”,则所有前导制表符将从输入行和包含的行中删除分隔符。这允许 shell 脚本中的此处文档以自然的方式缩进。