while 循环中的“tail -f | grep 错误”不起作用

ram*_*ram 3 grep scripting pipe tail

下面的命令没有给出任何结果。我想grep从文件中提取错误行并插入到表中。

不起作用的命令:

tail -f logfile.log | grep  ERROR|while read msg; do psql -d testdb -c insert into t values('$msg'); done
Run Code Online (Sandbox Code Playgroud)

但是如果我grep ERROR从命令中删除代码,它会按预期工作。我不确定发生了什么?

运行正常的命令:

tail -f logfile.log|while read msg; do psql -d testdb -c insert into t values('$msg'); done
Run Code Online (Sandbox Code Playgroud)

您可以假设文件中有以下数据:

ERROR
sql committed
ERROR
ERROR
error
...
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 6

两件事情:

  1. 正如问题中所写的那样,代码将插入文字字符串$msg(如果它有效的话),因为您在它周围使用了单引号。请改用双引号。在这里,我将整个语句放在双引号中,这将扩展$msg内部。shell 代码仍然脆弱,这取决于grep. $msg理想情况下,应正确清理in 字符串,以便单个'或其他特殊字符不会破坏语句(或更糟的是,请参阅下面来自用户cas 的评论)。

    tail -f logfile.log |
    grep -F 'ERROR' |
    while read msg; do
        psql -d testdb -c "insert into t values('$msg')"
    done
    
    Run Code Online (Sandbox Code Playgroud)

    当我们使用固定字符串进行搜索时,我还添加-Fgrep调用(这主要用于文档目的)。

  2. grep缓冲其输出,因此在其输出缓冲区已满之前它不会产生任何内容。这给人的印象是它实际上“不工作”,但它不会做任何事情,直到grep刷新它的输出缓冲区,一旦其中有足够的数据,它就会这样做。这是性能优化。

    GNU grep(以及相同实用程序的其他一些实现,例如在 OpenBSD 上)可以使用其--line-buffered选项进行行缓冲:

    tail -f logfile.log |
    grep --line-buffered -F 'ERROR' |
    while read msg; do
        psql -d testdb -c "insert into t values('$msg')"
    done
    
    Run Code Online (Sandbox Code Playgroud)

注意:我没有对此进行测试,因为我目前没有运行 PostgreSQL (?) 实例。

  • 第三件事:ERROR 消息的内容可能会破坏 SQL `insert` 命令(例如,如果其中包含单引号),甚至构成 SQL 注入威胁(例如,“ERROR something something”);删除表 t; --`)。我**非常强烈**推荐使用 perl 或 python 或**任何**其他具有支持 SQL 语句中变量占位符的数据库接口库的语言。 (2认同)
  • 使用 `File::Tail` 和 `DBI` + `DBD::Pg` 模块的 `perl` 脚本非常适合这样的工作。 (2认同)