【问题标题】:Why does `ack` not produce output when used with `bash` like this?像这样与 `bash` 一起使用时,为什么 `ack` 不会产生输出?
【发布时间】:2017-07-14 05:48:35
【问题描述】:

我猜这与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(来自期望)使其工作,我不明白:

> 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

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

【问题讨论】:

  • 这是一个ack 问题。尝试将ack 替换为grep 并按预期工作。
  • 看起来 ack 在运行 cat ack.sh | bash 时对 stdin 不是终端感到不高兴。我会为ack 提交一个错误文件。或者只使用grep ;)
  • 注意显式重定向ack的标准输入也可以解决问题:echo 'ack foobar file.txt &lt;&amp;-' | bashecho 'ack foobar file.txt &lt;/dev/null' | bash

标签: bash ack


【解决方案1】:

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

这个:

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

作品:

$ cat ack.sh | bash
foobar

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


为什么unbuffer“解决”了问题?

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 读取并查看传递给它的文件名。同样,imo 如果存在文件名参数,则根本不查看标准输入是正确的。

【讨论】:

  • I would expect that ack doesn't look at stdin when filename arguments are passed to it. 完全正确。
  • 你同意这是一个错误?
  • 不,这是故意的。如果 ack 没有得到文件名或目录,它会从当前目录开始在树中为您查找文件。只有在 stdin 上有东西可以使用时,它才会在 stdin 上查找。
  • 是的,但在这种情况下,我们传递文件名file.txt。在这种情况下,Imo ack 不能查看标准输入。
【解决方案2】:

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

引发此问题的用例是什么?

【讨论】:

  • 很高兴作者在 stackoverflow 上 :)
  • 嗨@AndyLester,将--noenv 放入我的脚本不会改变任何事情。我正在使用 ack 而不是 grep,因为我想要 --ignore-dir--ignore-file。我正在传输git diff origin/master | perl -ne &lt;find removed function names&gt; | ack 的输出,以确保我已经处理了所有使用它们的情况。
  • grep 有--ignore-dir--ignore-file,但它们被称为--exclude-dir--exclude。如果您正在输入ack,那么--ignore-dir--ignore-file 无论如何都不起作用。也许将您的整个脚本发布到 Google Groups 上的 ack-users 邮件列表中,我们可以帮助您完成它。
  • 而且--noenv 不会影响这里的任何内容。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    相关资源
    最近更新 更多