过去六个月左右,我在 bash 中组合搜索时遇到了一个问题。确切的示例与 Python 编程有关,但适用于任何类型的检测/操作。
假设我想要获取当前目录中所有 Python 文件的列表。这很简单:
find . -name '*.py'
现在,假设我只对包含字符串“psycopg”的 Python 文件感兴趣,例如因为我想从旧的 PostgreSQL 访问库过渡心理学到psycopg2. 仍然足够简单:
grep -l psycopg `find . -name '*.py'`
现在,假设我想列出这些文件的完整列表,以检查它们的日期戳,以了解我上次接触它们的时间。我也可以希望在 gedit 中打开它们,但让我们坚持列表:
ls -l `!!`
扩展为
ls -l `grep -l psycopg `find . -name '*.py'``
现在,会发生什么?答案:什么也没有。bash 提示符只是挂起。为什么会这样?这可能是一种错误的做事方式,但它曾经有效。我很确定它在 Ubuntu 10.10 或 10.04 之前有效。
答案1
问题在于嵌套的带反引号的命令替换。bash
首先尝试执行grep -l psycopg
(位于前两个反引号之间)。但是没有文件名 - 因此它需要输入stdin
(您可以通过输入 来尝试此操作psycopg
)。
您可以使用$(command)
命令替换的语法来避免此问题:
grep -l psycopg $(find . -name '*.py')
ls -l $(!!)
在这种情况下它可以嵌套。
答案2
反引号不能嵌套。第一个嵌入的命令是,grep -l psycopg
它将在 stdin 上监听数据,因为没有文件名。
我想说的是习惯使用$(this syntax)
而不是反引号,因为它们确实可以正确嵌套。
ls -l $(grep -l psycopg $(find . -name \*py))
答案3
通常以相反的方式执行,找到文件,在其中进行 grep,然后使用 finds ls:
find . -name '*.py' -exec grep -q psycopg {} ";" -ls
可以有特殊形式的输出(printf)并在 find 的手册页中列出。
答案4
$()
在或``
(命令替换)中使用输出多个文件名的命令总是错误的。请参阅http://mywiki.wooledge.org/ParsingLs解释为什么你不应该这么做。
另请阅读http://mywiki.wooledge.org/UsingFind和http://mywiki.wooledge.org/BashFAQ/020关于如何使用查找并正确处理文件名。
和不,
ls -l `grep -l psycopg `find . -name '*.py'``
在早期版本中也不可能起作用。
用户未知的回答展示了一种完成您所询问的任务的好而安全的方法。