如何强制 ssh 在远程系统而不是本地执行命令

如何强制 ssh 在远程系统而不是本地执行命令

我让 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 initgem 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 脚本中的此处文档以自然的方式缩进。

相关内容