新的十年:如何说出类似“find /path/ -name 'file.20{19,20}*”这样的内容(但有效)

新的十年:如何说出类似“find /path/ -name 'file.20{19,20}*”这样的内容(但有效)

概括:

  1. 给定的系统有很多带有名称的文本文件~= [type of file].[8-digit date]
  2. 为了搜索这些文件,我喜欢(并且想要保留)使用这个惯用法:(find /path/ -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'其中nnnn== 4 位年份)
  3. ...在过去的十年中,我也find跨年进行了全球合作,例如find /path/ -name 'file.201[89]*' -print | xargs ...
  4. ...但现在我无法find在 2019 年和 2020 年使用find /path/ -name 'file.20{19,20}*' -print | xargs ...
  5. ...尽管“大括号通配符”(正确的术语?)可以很好地工作ls

有没有一种{简洁,优雅}的方式来告诉find我想要什么,而不需要进行后期find清理(即我现在正在做的事情)

find /path/ -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...

? FWIW,我更喜欢一个与xargs.

细节:

我工作的系统有很多约定俗成的约定,这些约定早在我之前就已经存在,而且我无法改变。其中之一是,它有很多名称为 的文本文件~= [type of file].[8-digit date],例如woohoo_log.20191230.当在这些文件中搜索某些给定文本时,我通常(几乎总是)使用习惯用法find ... grep(通常使用 Emacs' M-x find-grep)。 (FWIW,这是一个 Linux 系统

$ find --version
find (GNU findutils) 4.4.2
...
$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)

如果我愿意的话,我目前缺乏改变其中任何一个的状态。)我经常有点知道手头上的事情的年份范围,因此会尝试限制find返回的内容(以加快处理速度),例如

find /path/ -type f -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'

其中nnnn== 4 位数年份。这个 WFM,我喜欢(并且想保留)使用上面的习语......特别是因为我也可以使用它来跨年搜索,例如

find /path/ -type f -name 'file.201[89]*' -print | xargs ...

但新的十年似乎正在打破这个习惯,而且(至少对我来说)最奇怪的是。 (当过去十年发生变化时,我并不在这里。)假设我选择了我想要的文本知道位于 2019 年的文件 && 2020 年的文件中(例如,我可以打开文件并查看文本)。如果我现在这样做

find /path/ -name 'file.20{19,20}*' -print | xargs ...

grep出乎意料地/令人烦恼地完成with no matches found,因为

$ find /path/ -name 'file.20{19,20}*' -print | wc -l
0

但如果我这样做

find /path/ -type f -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...

grep返回预期结果。这很好,但是......嗯......这只是丑陋的,特别是因为这个“大括号 glob”(如果此用法不正确或以其他方式被弃用,请纠正我)的工作原理ls!即,这显示了相关年份范围内的文件(即 2019..2020)

ls -al /path/file.20{19,20}*

因此我想知道:

  1. 我只是没有find为这个用例提供正确的 glob 吗?我需要告诉find它什么才能让它做ls有能力/正确地做的事情?
  2. 这是有问题吗xargs?如果是这样,我可以接受一个find ... -exec解决方案,但是......我的大脑在 的情况下工作得更好xargs,所以如果可能的话,我宁愿坚持下去。 (可以说我是弱智,但是-exec的语法让我的大脑受伤.)

答案1

使用zsh,您可以使用递归通配符及其<x-y>匹配十进制数字范围的通配符运算符:

grep -nHFe 'text I seek' /path/**/file.<2019-2020>*(D-.)

(D)to 也可以查看隐藏的(Dot)目录find;如果您不想要它们,大概您可以省略它,并且-.限制为常规的文件 ( .) 在符号链接解析 ( -) 后被识别。

请注意,它也会匹配 on file.00002020(因为这是 2019 到 2020 之间的十进制数字),并且像您的方法中的 on 一样,file.20201234file.2020匹配file.<2019-2020>后面跟着1234which matches *

标准(POSIXsh和实用程序)方法是:

find /path \( -name 'file.2019*' -o -name 'file.2020*' \) -type f \
  -exec grep -Fne 'text I seek' /dev/null {} +

(其中添加的效果与GNU强制显示文件名的/dev/null效果相同)grep-H

请注意, 的输出find -print与 的预期输入格式不兼容xargs。使用 GNU 实用程序,您可以使用find -print0xargs -r0,但这不是必需的,因为find -exec ... {} +具有相同的行为,更短且更便携。

答案2

在 中ls -al /path/file.20{19,20}*,它与 没有ls任何关系{19,20}*。在该命令中,shell 执行大括号扩展通配作为/path/file.20{19,20}*它没有被引用

bash-5.0$ set -x
bash-5.0$ echo {a,b}
+ echo a b
a b
bash-5.0$ ls {a,b}
+ ls a b
ls: cannot access 'a': No such file or directory
ls: cannot access 'b': No such file or directory
bash-5.0$ find -iname {a,b}
+ find -iname a b
find: paths must precede expression: `b'

find /path/ -name 'file.20{19,20}*',中'file.20{19,20}*'被引用,因此 shell 不理会它,然后find应用它自己的模式匹配规则,不支持大括号扩展。这里引用了GNUfind手册

模式 (' {}') 内的大括号不被视为特殊(即find . -name 'foo{1,2}'匹配名为 的文件foo{1,2},而不是文件foo1foo2.

如果你确实想使用大括号扩展来递归搜索目录,在 bash 中,你可以启用递归通配(globstar) (并且可能dotglob像这样查看隐藏目录find),并printf与 一起使用xargs

shopt -s globstar
printf "%s\0" /path/**/file.20{19,20}* | xargs -0 ...

或者您可以使用findwith-regex而不是-name一些find实现所支持的。使用 GNU find

find  /path -regextype posix-extended -regex '.*/file.20(19|20)[^/]*'

答案3

这不是您问题的一般情况答案,但可能有一种简单的方法来做到这一点,具体取决于您拥有多少文件历史记录。我在九月/十月找东西时经常遇到类似的情况。一种简单的解决方法是使用如下所示的 a 模式:

file.20[12][90]*

它并不相同,因为除了 2019 年和 2020 年之外,它还会匹配 2010 年和 2029 年。大概您还没有任何日期为 2029 年的文件。如果您的存档不能追溯到 2010 年,那么这在功能上应该是可以的相等的。

相关内容