在 shell 变量中使用管道运算符时出现意外结果

在 shell 变量中使用管道运算符时出现意外结果

我有一个进程,它将一些压缩的输出转储到 stdout。我对此输出的处理方式是将其通过管道通过 SSH 隧道发送到另一台计算机,然后将其转储到文件中。

就像这样:

/usr/bin/myapp | ssh root@remotemachine "cat > /path/to/output/file.gz"

当我ssh进入机器并调用此行时,一切都很顺利。但是当我把这个命令放在 shell 脚本中时,就像

#!/bin/sh
APP=/usr/bin/myapp
OPTS=--gzip
OUTPUT= "| ssh root@remotemachine \"cat > /path/to/output/file.gz\""
$APP $OPTS $OUTPUT

然后调用脚本,我在控制台上看到垃圾,我只能假设它是输出myapp,然后是这个

Unknown parameter '|'
Unknown parameter 'ssh'
Unknown parameter 'root@remotemachine'
Unknown parameter '"cat'
Unknown parameter '>'
Unknown parameter '/path/to/output/file.gz"'

我猜想 shell 将该$OUTPUT部分作为参数发送给它们,myapp而不是对它们执行操作。因此,这些“未知参数”不是来自myappshell,而是来自其他部分。

我该如何修复这个问题?

答案1

您的 shell 会按照特定顺序解析任何命令行。当它遇到时,$APP $OPTS $OUTPUT它会发现没有管道运算符;稍后这些变量会被展开并|出现,但它没有特殊含义,因为此时已经太晚了。

eval结果可以用(你的答案表明你已经发现了这一点)重新评估,但是eval可能会拼写错误evil

你原来的方法是有缺陷的,因为 shell 变量不是为了包含代码。函数是用于代码的。例如:

app=/usr/bin/myapp
opts=--gzip
output() { ssh root@remotemachine "cat > /path/to/output/file.gz"; }
$app $opts | output

笔记使用小写变量名是一种很好的做法

答案2

好的……我找到了我需要的东西。这是eval命令。这实际上是答案这里

因此,可以按如下方式修改脚本:

#!/bin/sh
APP=/usr/bin/myapp
OPTS=--gzip
OUTPUT= "| ssh root@remotemachine \"cat > /path/to/output/file.gz\""
eval "$APP $OPTS $OUTPUT"

相关内容