我想找到包含数字的文件名并将它们列出在数字范围内。例如,在我的目录中有:**
Ion_001_rawlib.bam
Ion_002_rawlib.bam
Ion_003_rawlib.bam
Ion_004_rawlib.bam
Ion_005_rawlib.bam
...
Ion_020_rawlib.bam
**
我只想列出从 003 到 005 的 Ion 文件名。我尝试这样做:
find -name '*Ion_*[3-5]*rawlib.bam'
但并没有产生预期的效果。您知道是否可以执行吗?谢谢。
答案1
使用zsh
shell,您可以执行以下操作:
print -rC1 Ion_<3-5>_rawlib.bam
其中是一个全局运算符,它匹配给定范围(从到,包括)<x-y>
内的正整数的文本十进制表示形式。x
y
递归地:
print -rC1 -- **/Ion_<3-5>_rawlib.bam
((D)
如果您还想在隐藏文件夹中查找这些文件,或者(N)
如果您不想在没有匹配文件时将其视为错误,请添加)。
通过find
支持-regex
谓词的实现,您可以执行以下操作:
LC_ALL=C find . -regex '.*/Ion_0*[345]_rawlib\.bam'
(匹配包含 0 个或多个 ( *
) 字节(.
带有LC_ALL=C
)、后跟/Ion_
0 个或多个 ( *
) 0
、后跟3
、4
或5
字符之一的文件路径,后跟rawlib.bam
)。
在这里,对于 3..5 范围来说相对容易,但是对于像 78..123 这样的范围来说会变得更加痛苦(并且您会遇到兼容性问题,因为find
支持-regex
使用不同格式的正则表达式的少数实现) )。
标准find
仅支持-name
和-path
用于匹配文件名,它是使用基本的 shell 通配符而不是正则表达式来完成的,但通配符没有相当于*
regexp 运算符(0 个或多个前面的原子),其*
运算符相当于 regexp .*
(0 个或多个字符),因此Ion_*[3-5]_rawlib.bam
将匹配 onIon_9994_rawlib.bam
例如作为*
匹配 on 999
。
然而,在这个简单的情况下,您可以使用多种模式和否定来完成此操作,例如:
LC_ALL=C find . -name 'Ion_*[345]_rawlib.bam' \
! -name 'Ion_*[!0]*?_rawlib.bam'
非递归:
LC_ALL=C find . ! -name . -prune \
-name 'Ion_*[345]_rawlib.bam' \
! -name 'Ion_*[!0]*?_rawlib.bam'
要查找名称中任意位置包含整数十进制表示形式的文件,您需要一个与该范围匹配的模式(如x
s ),但还要确保该模式不被其他数字包围。例如确实包含、和,所有这些都匹配。y
zsh
<x-y>
foo305.txt
3
05
5
<3-5>
在 中zsh
,那就是:
print -rC1 -- (|*[^0-9])<3-5>(|[^0-9]*)
也就是说<3-5>
(匹配 3, 03, 003...),后面紧跟任何内容或以非数字结尾的字符串,后面紧跟任何内容或以非数字开头的字符串。
使用BSD find
:
LC_ALL=C find -E . -regex '.*/([^/]*[^0-9])?0*[3-5]([^0-9][^/]*)?'
与 GNUfind
相同,但替换-E .
为. -regextype posix-extended
.
使用 busybox find
(尽管取决于它的编译方式):
busybox find . -regex '.*/\([^/]*[^0-9]\)\?0*[3-5]\([^0-9][^/]*\)\?'
另一种方法是使用find
报告文件列表,但使用更高级的语言,例如perl
过滤该列表:
find . -print0 | perl -l -0ne '
if (m{[^/]*\z}) {
for $n ($& =~ /\d+/g) {
if ($n >= 3 && $n <= 5) {
print;
next LINE;
}
}
}'
此处,用于perl
从每个文件的基本名称中提取所有十进制数字序列,如果这些数字序列中至少有一个表示 3..5 范围内的数字,则输出文件。