find 命令中的 Unix 括号扩展

问题描述

这工作正常:

$ echo email_{ldn,nyk,asp}.log

同样,我想找到略有不同的文件名:

$ find ~ -type f -name email_{ldn,asp}.log

但是上面的命令会导致错误

find: paths must precede expression: email_nyk.log

非常感谢 find 命令中有关大括号扩展的任何帮助。

解决方法

错误消息是由您的 shell 扩展模式引起的。

假设您的当前目录中有 email_ldn.logemail_nyk.logemail_asp.log 文件,您的命令

find ~ -type f -name email_{ldn,nyk,asp}.log

将扩展为

find ~ -type f -name email_ldn.log email_nyk.log email_asp.log

这会导致错误消息。

为了防止 shell 扩展模式,您必须引用该模式。不幸的是,find 不支持在大括号中包含替代项列表的模式,因此将此模式与 find 一起使用将无法按您预期的那样工作。

find ~ -type f -name "email_{ldn,asp}.log" # Does not work as intended.
find ~ -type f -name "email_*.log" # This would work,but matches other files as well.

如果您有 GNU find,则可以使用正则表达式代替。

find ~ -type f -regextype posix-extended -regex ".*/email_(ldn|nyk|asp).log"
,

如果你想用一个前缀查找所有文件,你可以使用这个命令:

find ~ -type f -name "email_*.log"

在这种情况下,您不需要使用大括号。不要忘记在名称模式前后放置 "(引号)。

find 不支持大括号来设置替代项,就像 shell 一样。因此,如果您想查找特定文件,可以分两步完成:首先查找所有带有“email”前缀的文件,然后使用 grep 查找特定文件。试试这个: find ~ -type f -name "email*" | egrep "email_(ldn|asp|nyk).log"

,

大括号扩展不是做这种事情的方式,eval是邪恶的,但你可以这样做:

eval find ~ -type f -and \\\( -false "-or -name "email_{ldn,asp}.log \\\)

主要思想是 -name email_ldn.log email_nyk.log email_asp.log 不起作用,因为您希望表达式为 -name email_ldn.log -or -name email_nyk.log -or -name email_asp.log,因此您使用大括号扩展创建该表达式。但是 find 接收 -or -name email_???.log 作为单个参数而不是 3 个参数,因此您需要使用 eval 强制分词。总的来说,这是一个令人讨厌、丑陋的解决方案。

,

最终在征服过程中实现了,你们中的一些人建议使用eval,但我认为使用xargs会更好:

由于目的是找到匹配大括号扩展的文件并在之后执行很少的命令,所以 xargs 非常适合这个目的。

$ ls ~/email_{ldn,asp}.log | xargs -I %% sh -c 'chomd 644 %% && cp -arf %% ~/feed_dir'