![如何根据文件名范围查找文件?](https://linux22.com/image/35317/%E5%A6%82%E4%BD%95%E6%A0%B9%E6%8D%AE%E6%96%87%E4%BB%B6%E5%90%8D%E8%8C%83%E5%9B%B4%E6%9F%A5%E6%89%BE%E6%96%87%E4%BB%B6%EF%BC%9F.png)
我有一些带有数字名称的文件:2341a.po
、4567211someword.po
、0012.po
等。我想根据数字范围查找一组文件。例如[126 - 363]
。
通常我使用正则表达式find
。任何数值范围都可以由两个正则表达式和[N, M]
组成。larger than N
less than M
大于N的:
如果,那么我首先为所有人N = vxyz
进行匹配value > V000, (V=v+1)
[V-9]\d{3,}
然后将vX00
, X=x+1
, 与v[X-9]\d\d
然后将vxY0
, Y=y+1
, 与vx[Y-9]\d
最后vxy[z-9]
例子:
为了匹配number>=234
,我使用:
`^(0*([3-9]\d{2,}|2[4-9]\d|23[4-9]))`
小于M的:
基于类似的逻辑,我们将有:
^(0*(vxy[0-z]|vx[0-Y]\d|v[0-X]\d\d|[1-V]\d\d|\d{1,3}))[^0-9]
和Y=y-1,X=x-1,V=v-1
例如,以下命令将查找 [253, 326] 之间的任何文件:
find . -maxdepth 1 -type f -regextype posix-extended -iregex '^\./0*([3-9][0-9]{2,}|2[6-9][0-9]{2,}|25[3-9]).*' -iregex '^\./0*(32[0-6]|3[0-1][0-9]|[0-2][0-9][0-9]|[0-9]{1,2})[^0-9].*'
然而,这种方法对于处理长数字来说太烦人了。有没有更好、更简单的方法来做到这一点?
答案1
和zsh
:
setopt extendedglob # best in ~/.zshrc
ls -ld -- <126-253>(*.po~[0-9]*)
也就是说,十进制数字 126 到 253(也接受 000126),后跟以十进制数字结尾.po
且不以十进制数字开头的内容)。
递归地,包括隐藏目录和仅常规文件:
ls -ld -- **/<126-253>(*.po~[0-9]*)(D.)
如果zargs
您遇到arg list too long
错误。
要使用变量而不是文字数字,您不能这样做。该<$low-$high>
<x-y>
运算符与重定向运算符重叠(echo <3-4> z
在 POSIX shell 中,echo
使用从3-
文件重定向的输入和 fd 4 进入z
)运行,zsh
尝试通过仅接受文字数字来最小化冲突风险。但是,您可以将该运算符用作globsubst
ing 扩展的一部分,例如:
low=126 high=253
ls -ld -- ${~:-"<$low-$high>"}(*.po~[0-9]*)
其中${~expansion}
启用globsubst
(允许扩展进行通配)是expansion
的${:-"text"}
一种特殊形式,${var:-default}
可以将扩展扩展到任意text
。
答案2
您可以生成一个包含要查找的数字的文件列表,并将它们放在参数列表中以供find
使用xargs
。例如,使用,与问题中bash
使用 as 等效的是:-maxdepth 1
echo {253..326} | xargs sh -c 'find "$@" -type f -maxdepth 0' sh
请注意,您可以使用-I
选项xargs
(ie xargs -I{} find {} -type f
),但 GNUxargs
强制-L 1
使用此选项,这意味着为每个参数启动单独的查找过程。使用sh
可以解决这个问题。
对于任意深度,您可以执行以下操作:
printf -- '-o -name %d ' {254..326} |
xargs -n 3000 sh -c 'find -type f \( -name 253 "$@" \)' sh
应选择参数-n
(每个命令添加的最大参数数量),以便限制参数列表结构的大小xargs
。如果太大,则可能会由于参数列表的总体大小而不是参数数量而达到限制。它应该是 3 的倍数,这样列表中就不会留下尾随-o
或。-name
答案3
对格雷姆答案的强力扩展:
find . -type f -regextype posix-awk -regex ".*/0*($(seq -s'|' 254 456)).*"
如果您需要 POSIX ,您可以使用\|
代替|
和\(\)
代替()
(但是,这seq
不是 POSIX,不是吗?)。
$ find . -maxdepth 2 -type f -regextype posix-awk -regex ".*/0*($(seq -s'|' 254 456)).*"
./.fontconfig/3047814df9a2f067bd2d96a2b9c36e5a-le32d4.cache-3
./.fontconfig/3830d5c3ddfd5cd38a049b759396e72e-le32d4.cache-3
./.fontconfig/385c0604a188198f04d133e54aba7fe7-le32d4.cache-3
./Documents/374620-63301.pdf
./4567211someword.po
唔。看起来我们应该添加一个非数字字符来标记数字的结尾。也许".*/0*($(seq -s'|' 254 456))[^0-9].*"
?
答案4
find | perl -ne 'print if(m!^\./(\d+)! and $1 > 126 and $1 <363)'
...可能会添加其他答案中提出的一些好主意。
正则表达式可能需要一些调整(例如^\./(\d+)\w*.po$
:)