捕获远程ssh命令的输出失败

时间:2019-01-15 21:17:47

标签: bash ssh

我正在尝试在bash脚本中捕获远程执行命令的输出,以便该脚本可以对结果进行某种处理,并且对结果感到困惑:

$ COMMAND="ssh localhost \"echo 'hello'\""
$ OUTPUT=$($COMMAND)
bash: echo 'hello': command not found

使用反引号会产生稍微不同的结果:

$ `ssh localhost "echo 'hello'"`
-bash: hello: command not found

但是命令运行时没有任何包装:

$ ssh localhost "echo 'hello'"
hello

我怀疑我误解了有关如何执行这些命令的一些基本知识。我在这里做错了什么吗?还是有更好的方法?

1 个答案:

答案 0 :(得分:2)

问题

执行以下操作时不会评估行号("..."

$($COMMAND)

远程Bash看到的是两个参数:"echo'hello'",而不是您期望的echo 'hello'

建议的解决方案:数组

在您的情况下,我建议使用数组:

COMMAND=( ssh localhost "echo 'hello'" )
OUTPUT=$( "${COMMAND[@]}" )

(...)中的单词是数组的元素。在这种情况下,echo 'hello'被视为单个元素:在赋值期间立即评估引号。然后,当您执行"${COMMAND[@]}"时,每个元素都将作为参数传递而没有改变。

还有其他几种方法可以解决此问题,例如使用eval以便对引号进行评估,但是以我的经验,使用数组是构建和执行命令的最安全,最简单的方法。使用数组可以很容易地防止shell注入攻击,防止不必要的扩展,防止在有空格的情况下破坏单词。唯一的缺点是数组并非在每个shell中都可用。

问题的说明

原因是扩展名(即$COMMAND)不评估引号。

这个简单的示例说明了这一点,在该示例中,我们每行打印一个参数:

$ COMMAND="ssh localhost \"echo 'hello'\""
$ for x in $COMMAND; do echo "$x"; done
ssh
localhost
"echo
'hello'"

通过使用数组代替:

$ COMMAND=( ssh localhost "echo 'hello'" )
$ for x in "${COMMAND[@]}"; do echo "$x"; done
ssh
localhost
echo 'hello'

在数组中,echo 'hello'在一行上(即它是单个参数),而用一个简单的字符串代替了"echo'hello'"