反引号无法处理变量中的管道

Backticks can't handle pipes in variable

我在 bash 中使用 CAT 命令的一个脚本有问题。

这个有效:

 #!/bin/bash
fil="| grep LSmonitor";
log="/var/log/sys.log ";
lines=`cat $log | grep LSmonitor | wc -l`;
echo $lines;

输出:139

这不是:

#!/bin/bash
fil="| grep LSmonitor";
log="/var/log/sys.log ";

string="cat $log $fil | wc -l";
echo $string;
`$string`;

输出:

cat /var/log/sys.log | grep LSmonitor | wc -l
cat: opcion invalida -- 'l'
Pruebe 'cat --help' para mas informacion.

$fil在这个例子中是一个静态参数,但是在真实的脚本中,参数是从html POST中获取的,如果我打印我可以看到$fil的内容是正确的。

在这种情况下,由于您将管道构建为字符串,因此您需要:

eval "$string"

但是不要这样做!!!! -- 有人可以轻松进入过滤器

; rm -rf *

然后你就完蛋了。

如果你想要一个基于正则表达式的过滤器,让用户只输入正则表达式,然后你会做:

grep "$fil" "$log" | wc -l

尝试使用 eval(摘自 )。

它看起来像是将 | 解释为字符串,而不是管道,所以当它到达 -l 时,它会将其视为您试图传入 -l cat 而不是 wc.

其他答案概述了您不应该这样做的原因。

grep LSmonitor /var/log/syslog | wc -l 将满足您的需求。

首先,请允许我说这听起来是个糟糕的主意:

[…] in real script, parameter is get from html form POST, […]

您不应允许 POST 请求的内容被您的 shell 运行。这是一个巨大的攻击媒介,无论您采用何种机制来保护它,都可能没有您想象的那么有效。

其次,|内部变量不被视为特殊变量。这不是反引号特有的。参数扩展(例如,将 $fil 替换为 | grep LSmonitor)发生在 命令被解析和大部分处理之后。对参数扩展的结果进行了一些 post 处理(包括 "word splitting",这就是为什么 $fil 等同于三个参数 '|' grep LSmonitor 而不是单个参数 '| grep LSmonitor'),但没有你描述的那么戏剧化。因此,例如,这个:

pipe='|'
echo $pipe cat

打印这个:

| cat

既然你的用例太可怕了,我有点想解释你如何做你想做的事——我想你会过得更好不是 这样做——但由于 Stack Overflow 答案旨在对更多人有用,而不仅仅是原来的 poster,下面是一个如何做到这一点的示例。我鼓励 OP 不要继续阅读。


fil='| grep LSmonitor'
log=/var/log/sys.log

string="cat $log $fil | wc -l"
lines="$(eval "$string")"
echo "$lines"