在过去六个月左右的时间里,我在 bash 中组合搜索时遇到了问题。确切的示例与 Python 编程有关,但适用于任何类型的检测/操作。
假设我想要我所在目录中所有 Python 文件的列表。这很简单:
find . -name '*.py'
Run Code Online (Sandbox Code Playgroud)
现在,假设我只对那些包含字符串“psycopg”的 Python 文件感兴趣,例如因为我想从旧的 PostgreSQL 访问库psycopg 转换到psycopg2。还是很简单的:
grep -l psycopg `find . -name '*.py'`
Run Code Online (Sandbox Code Playgroud)
现在,假设我想列出这些文件的完整列表,以检查它们的日期戳以查看我上次接触它们的时间。我也希望在 gedit 中打开它们,但让我们坚持以下列表:
ls -l `!!`
Run Code Online (Sandbox Code Playgroud)
扩展到
ls -l `grep -l psycopg `find . -name '*.py'``
Run Code Online (Sandbox Code Playgroud)
现在,会发生什么?答:没什么。bash 提示只是挂起。这是为什么?这可能是一种错误的做事方式,但它曾经奏效。我很确定它可以在 Ubuntu 10.10 或 10.04 之前运行。
小智 6
问题是带有反引号的嵌套命令替换。bash
首先尝试执行grep -l psycopg
(在前两个反引号之间)。但是没有文件名 - 因此它需要输入stdin
(您可以通过输入来尝试psycopg
)。
您可以通过使用$(command)
命令替换的语法来避免此问题:
grep -l psycopg $(find . -name '*.py')
ls -l $(!!)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,它可以嵌套。
反引号不嵌套。第一个嵌入的命令grep -l psycopg
将在 stdin 上侦听数据,因为没有文件名。
我会说习惯使用$(this syntax)
而不是反引号,因为它们可以正确嵌套。
ls -l $(grep -l psycopg $(find . -name \*py))
Run Code Online (Sandbox Code Playgroud)
通常以相反的方式执行,找到文件,在其中使用 grep,然后使用 find ls:
find . -name '*.py' -exec grep -q psycopg {} ";" -ls
Run Code Online (Sandbox Code Playgroud)
特殊形式的输出是可能的 (printf) 并在 find 的联机帮助页中列出。