为什么 `ack` 在与这样的 `bash` 一起使用时不产生输出?

Why does `ack` not produce output when used with `bash` like this?

我猜这与 ack 无关,但与 bash:

更多

这里我们创建 file.txt 包含字符串 foobar 所以 ack 可以在其中找到 foobar:

> echo foobar > file.txt
> echo 'ack foobar file.txt' > ack.sh
> bash ack.sh
foobar
> bash < ack.sh
foobar

到目前为止一切顺利。但是为什么 ack 在里面找不到这样的东西呢?

> cat ack.sh | bash
(no output)

> echo 'ack foobar file.txt' | bash
(no output)

为什么在后两种情况下 ack 找不到 foobar

在前面加上 unbuffer (from expect) 让它工作,我不明白:

> echo 'unbuffer ack foobar file.txt' | bash
foobar

更陌生:

> cat ack2.sh
echo running
ack foobar file.txt
echo running again
unbuffer ack foobar file.txt

# Behaves as I'd expect
> bash ack2.sh
running
foobar
running again
foobar

# Strange output
> cat ack2.sh | bash
running
unbuffer ack foobar file.txt

这个输出是怎么回事?它回显 unbuffer ack foobar file.txt 而不是 running again?嗯?

ack 感到困惑,因为标准输入是管道而不是终端。您需要传递 --nofilter 选项以强制 ack 将 stdin 视为 tty。

这个:

# ack.sh
ack --nofilter foobar file.txt

作品:

$ cat ack.sh | bash
foobar

如果你问我,这种行为是相当出乎意料的。当有人理解我不 atm 的 ack 的概念时,可能是预期的。我希望 ack 在将文件名参数传递给它时不会查看标准输入。


为什么会出现unbuffer"solve"的问题?

unbuffer,紧随其后的是 man page,不尝试从标准输入读取:

  Normally, unbuffer does not read from stdin.  This  simplifies  use  of
   unbuffer in some situations.  To use unbuffer in a pipeline, use the -p
   flag. ...

看起来 ack 也试图 对这里的 stdin 很聪明。如果它是空的,它不会从 stdin 读取并查看传递给它的文件名。同样,如果存在文件名参数,则完全不查看标准输入是正确的。

这里最大的不匹配是 ack 从未打算在 shell 脚本中使用。它意味着作为人类的命令行工具。这意味着它为人类做了一些假设和优化。例如,默认情况下 ack 的输出是不同的,如果它去终端与在管道中重定向。在 shell 脚本中使用 ack 也存在危险,因为它的行为可能会受到 ackrc 文件和环境变量的影响。如果你打算在脚本中使用 ack,你应该使用 --noenv 标志。更好的是,对于 shell 脚本,我会使用普通的 ol' grep。

提出这个问题的用例是什么?

我同意这是一个错误 – ack 可以查看标准输入,但是以 NON BLOCKING 方式。挂在空的管道上是一个错误……