为什么 `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 方式。挂在空的管道上是一个错误……
我猜这与 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 方式。挂在空的管道上是一个错误……