通过将行传递给外部程序来过滤行的程序?

Mic*_*and 5 command-line shell filter

我正在寻找一个程序来使用外部程序来过滤流的行 - 几乎是一个版本grep,对于每一行,根据指定的程序是否以零退出代码退出(例如find'小号-exec选项)。

我知道我可以通过使用循环和子shell在shell中执行此操作:

some-program |(while read line; do
    if predicate "$line"; then
        echo "$line"
    fi
done)
Run Code Online (Sandbox Code Playgroud)

我想知道的是,是否有一个程序可以让我使这更简单:

some-program |filter predicate
# want negation as well
some-program |filter ! predicate
Run Code Online (Sandbox Code Playgroud)

有人会认为增强的 Sed 可能支持这一点,询问“它是否传递模式空间?”,但 GNU Sed 似乎没有这样的功能。

是否有这样的程序我还没有找到,或者我只需要在 shell(或 perl)中执行它?

Gil*_*il' 1

shell 是非常适合这项工作的工具。请注意不要破坏空格和反斜杠。

while IFS= read -r line; do
  if predicate "$line"; then printf '%s\n' "$line"; done
done
Run Code Online (Sandbox Code Playgroud)

您也可以使用 awk。请务必引用每一行,因为它将被传递到 shell(下面的代码片段在该行周围放置单引号,并用 ; '\''is\047替换该行中的单引号')。因为每个命令调用都通过 shell,所以我预计这会比纯 shell 方法慢,即使 awk 解析行可能更快。但我还没有做任何基准。

awk '{quoted=$0; gsub(/\047/, "\047\\\\\047\047")}
     !system("predicate \047" $0 "\047")'
Run Code Online (Sandbox Code Playgroud)

  • @NeilMayhew 几乎,但是 `echo "$line"` 在某些情况下可能会破坏它的参数(如果 `$line` 是 `-e` 或 `-E` 或 `-n`;并且对于某些 shell,它可能会做反斜杠插值),而 `printf '%s\n' "$line"` 可靠地打印 `$line` 后跟一个换行符。 (2认同)