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
我怀疑我误解了关于如何执行这些命令的一些非常基本的东西。我在这里做错了什么,还是有更好的方法来做到这一点?
解决方案
问题
"..."
执行以下操作时不会评估引号 ( ):
$($COMMAND)
远程 Bash 看到的是两个参数:"echo
和'hello'"
,echo 'hello'
与您预期的不同。
建议的解决方案:数组
在您的情况下,我建议使用数组:
COMMAND=( ssh localhost "echo 'hello'" )
OUTPUT=$( "${COMMAND[@]}" )
其中的单词(...)
是数组的元素。在这种情况下,echo 'hello'
可以看到单个元素:在赋值期间立即评估引号。然后,当你这样做时"${COMMAND[@]}"
,每个元素都将作为参数传递,而不会被触及。
还有其他几种方法可以解决此问题,例如使用eval
以便评估引号,但根据我的经验,使用数组是构建和执行命令的最安全和最简单的方法。使用数组很容易防止外壳注入攻击,防止不必要的扩展,防止有空格时单词被破坏。唯一的缺点是数组并非在每个 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'"
拆分。
推荐阅读
- loops - gnuplot plot 循环通过轴
- python - 在 TensorFlow 中使用图像批处理进行多次运行
- xaml - Xamarin:StaticResource:“FontSize”没有属性、可绑定属性或事件?
- r - 如何在自定义函数中重命名列表对象?
- c - GdkPixbuf 改变不透明度
- eclipse - Eclipse 调试模式挂起/失败
- javascript - 在单引号之前插入字符串的反斜杠,Node v8.11.4
- ios - 应用程序已准备好销售,但仍显示 Beta 测试拒绝通知
- vagrant - 你如何通过 Vagrant 设置 VM 名称?
- windows - 通过 chef recipe 调用,SQLPLUS 无法识别 Windows 12R2 中的 Oracle_Home 环境变量