为什么使用 BSD grep 时 `--exclude-dir "_book"` 可以工作,但 `--exclude-dir={_book}` 却失败?

为什么使用 BSD grep 时 `--exclude-dir "_book"` 可以工作,但 `--exclude-dir={_book}` 却失败?

我的 grep 版本是grep (BSD grep) 2.5.1-FreeBSD,我的操作系统是OSX 10.13.3 (17D47)

我有一个 gitbook 存储库,并且有一个名为_book我想在使用 grep 时忽略的临时目录。

当我使用 时grep -Fnrl mysql ./ --exclude-dir={_book},它没有排除该_book目录。结果看起来像

...
.//UTILITIES/my_utils/shell_scripts/get_several_days_mysql_data_log.sh
.//_book/search_jieba_index.dat
.//_book/LANGUAGES/awk/awk_magic.html

但该命令grep -Fnrl mysql ./ --exclude-dir "_book"给了我我所期望的结果,结果看起来像

...
.//UTILITIES/my_utils/shell_scripts/get_several_days_mysql_data_log.sh

我在 stackoverflow 上搜索过,发现一个问题提到了第一个命令样式并获得了 3 个赞成票,所以我猜它在某些情况下有效。
问题链接是:使用带有 --exclude-dir 标志的 grep 来排除多个目录

为什么会发生这种情况?
如果我想使用第一种命令方式排除成功怎么办_book

答案1

那篇文章正在利用 bash 的大括号扩展:

$ printf "%s\n" --exclude-dir={a,b,c}
--exclude-dir=a
--exclude-dir=b
--exclude-dir=c

但是,当只有一个元素时,不会应用大括号扩展,并且大括号保持原样:

$ printf "%s\n" --exclude-dir={a}
--exclude-dir={a}

由于大括号扩展是 bash(和其他一些 shell)的功能,而不是 grep 的功能,因此对于 grep 来说,它看起来像是您告诉它排除名为{_book}.

答案2

这些并不是不同的“命令风格”。他们正在利用一个巴什特征,而不是grep特征。

通过运行以下命令来阅读它:

LESS='+/Brace Expansion' man bash

当大括号内有逗号分隔的值时,您的grep在看到它们之前将它们扩展到多个参数。

由于您只传递一个目录,因此不需要大括号扩展。

当您使用的大括号之间只有一个项目(没有逗号和双句点来指示范围)时,您的 shell 会单独保留大括号。您需要传递grep文字名称{_book},这不是您想要排除的目录。


值得一提的是,您也不需要双引号。

grep -Fnrl mysql ./ --exclude-dir _book

...会工作得很好。

双引号不会造成任何损害,但也不是必需的。你可以用它们全部参数具有相同的结果,因为引号在 shellgrep看到它们之前就被删除了。

grep '-Fnrl' "mysql" './' "--exclude-dir" \_\b\o\o\k

您甚至可以引用命令名称本身'grep',尽管它有一个轻微地不同的含义。具体来说,它抑制别名查找。例如,在 Ubuntu 系统上,grep通常别名为grep --color=auto.引用"grep"(或其任何部分)将绕过此别名。

gr\ep -Fnrl mysql ./ --exclude-dir _book

这个故事的寓意是,了解您所使用的语言的引用规则。

或者您可能会“犯”错误并产生令人困惑的结果。

相关内容