Tom*_*che 3 find gnu wildcards
概括:
~=
[type of file].[8-digit date]
。find /path/ -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'
其中nnnn
== 4 位数字年份)find
像find /path/ -name 'file.201[89]*' -print | xargs ...
find
在 2019 年和 2020 年与find /path/ -name 'file.20{19,20}*' -print | xargs ...
ls
!是否有一种{简洁、优雅}的方式来告诉find
我想要什么,而无需进行后期find
清理(即我现在正在做的事情)à la
find /path/ -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...
Run Code Online (Sandbox Code Playgroud)
? FWIW,我更喜欢与xargs
.
细节:
我在一个有很多约定的系统上工作,这些约定早在我之前并且我无法改变。其中之一是,它有很多带有名称的文本文件~=
[type of file].[8-digit date]
,例如woohoo_log.20191230
. 在这些文件中搜索某些给定文本时,我通常(如在,几乎总是)使用find ... grep
习语(通常使用 Emacs' M-x find-grep
)。(FWIW,这是一个带有
$ find --version
find (GNU findutils) 4.4.2
...
$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)
如果我愿意,我目前缺乏更改其中任何一个的状态。)我经常有点知道手头问题的年份范围,因此会尝试限制find
返回的内容(以加快处理速度),例如(例如)
find /path/ -type f -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'
Run Code Online (Sandbox Code Playgroud)
其中nnnn
== 4 位数字年份。这个 WFM,我喜欢(并想继续)使用上述习语......特别是因为我也可以用它来跨年搜索
find /path/ -type f -name 'file.201[89]*' -print | xargs ...
Run Code Online (Sandbox Code Playgroud)
但是这个新的十年似乎打破了这个习惯,而且(至少对我来说)最奇怪的是。(当过去十年发生变化时,我并不在这里。)假设我选择了我知道在 2019 年的文件中的文本&& 来自 2020 年的文件(例如,我可以打开文件并查看文本)。如果我现在做
find /path/ -name 'file.20{19,20}*' -print | xargs ...
Run Code Online (Sandbox Code Playgroud)
grep
意外/恼人地完成with no matches found
,因为
$ find /path/ -name 'file.20{19,20}*' -print | wc -l
0
Run Code Online (Sandbox Code Playgroud)
但如果我这样做
find /path/ -type f -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...
Run Code Online (Sandbox Code Playgroud)
grep
返回预期的结果。这很好,但是......嗯......这只是丑陋的,尤其是因为这个“花括号球”(如果这种用法不正确或以其他方式被弃用,请纠正我)从ls
!即,这向我显示了相关年份范围内的文件(即 2019..2020)
ls -al /path/file.20{19,20}*
Run Code Online (Sandbox Code Playgroud)
因此我想知道:
find
为这个用例提供正确的 glob 吗?我需要告诉find
什么才能让它做ls
有能力/正确做的事情?xargs
吗?如果是这样,我可以接受一个find ... -exec
解决方案,但是……我的大脑用 更好地工作xargs
,所以如果可能的话,我更愿意坚持下去。(叫我弱智,但它-exec
的语法让我的大脑受伤。)Sté*_*las 12
使用zsh
,您可以使用递归<x-y>
通配符及其匹配十进制数范围的通配符:
grep -nHFe 'text I seek' /path/**/file.<2019-2020>*(D-.)
Run Code Online (Sandbox Code Playgroud)
((D)
也可以查看隐藏的(D
ot)目录find
;如果您不想要它们,大概可以省略它,并且-.
限制为在符号链接解析()之后识别的常规文件.
(-
))。
请注意,它也将匹配file.00002020
(因为这是 2019 年和 2020 年之间的十进制数),就像您的方法一样,file.20201234
因为它的file.2020
which 匹配,file.<2019-2020>
然后是1234
which 匹配*
。
标准(POSIXsh
和实用程序)方法是:
find /path \( -name 'file.2019*' -o -name 'file.2020*' \) -type f \
-exec grep -Fne 'text I seek' /dev/null {} +
Run Code Online (Sandbox Code Playgroud)
(其中添加/dev/null
与 GNUgrep
的效果相同-H
以强制显示文件名)
请注意, 的输出find -print
与 的预期输入格式不兼容xargs
。使用 GNU 实用程序,您可以使用find -print0
and xargs -r0
,但这不是必需的,因为它find -exec ... {} +
具有相同的行为,更短且更便携。
在 中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'
Run Code Online (Sandbox Code Playgroud)
在find /path/ -name 'file.20{19,20}*'
,'file.20{19,20}*'
被引用,所以 shell 不理会它,find
然后应用它自己的模式匹配规则,不支持大括号扩展。这里引用GNUfind
手册:
模式 ('
{}
')内的大括号不被认为是特殊的(即find . -name 'foo{1,2}'
匹配名为 的文件foo{1,2}
,而不是文件foo1
和foo2
.
如果你真的想用括号展开递归搜索目录,在bash,您可以启用递归通配(globstar
)(并可能dotglob
寻找到隐藏的目录一样find
会),并使用printf
具有xargs
:
shopt -s globstar
printf "%s\0" /path/**/file.20{19,20}* | xargs -0 ...
Run Code Online (Sandbox Code Playgroud)
或者您可以使用find
with-regex
而不是-name
由一些find
实现支持。使用 GNU find
:
find /path -regextype posix-extended -regex '.*/file.20(19|20)[^/]*'
Run Code Online (Sandbox Code Playgroud)