我想保留名称匹配的文件[0-9A-Z]{1,2}_\d{4}_\w+?\.dat
,例如,A1_2001_pm23aD.dat
,K_1998_12.dat
,并删除其余文件。
但是,ls
和rm
命令不支持此类正则表达式。我怎样才能做到这一点?
答案1
使用扩展的 glob:
shopt -s extglob
printf '%s\n' !([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat)
这将打印所有不 ( !
) 匹配的文件/目录名称,[[:digit:][:upper:]]
后跟零或一,后跟 s之间的[[:digit:][:upper:]]
4 ,然后在扩展名之前跟随一个或多个。 如果你想递归搜索:[[:digit:]]
_
[[:alnum:]]
.dat
shopt -s globstar
shopt -s extglob
printf '%s\n' **/!([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat)
或者,使用gnu find
(您可以使用正则表达式):
find . -regextype egrep ! -regex '.*/[[:digit:][:upper:]]{1,2}_[[:digit:]]{4}_[[:alnum:]]+\.dat$'
答案2
有很多方法可以做到这一点。您可以使用理解正则表达式的脚本语言。例如,在 Perl 中:
perl -le 'unlink(grep(!/[0-9A-Z]{1,2}_\d{4}_\w+?.dat/,@ARGV))' *
这将查找所有文件(不是子目录) 在当前目录中,收集那些与正则表达式不匹配的内容并将其删除。
您也可以使用 bash 执行类似的操作,只需将正则表达式转换为 POSIX ERE:
for f in *; do
[[ "$f" =~ [0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat ]] || rm "$f";
done
请注意,在您的正则表达式中,\w+?.dat
将尝试匹配尽可能小的字母数字字符串任何字符和dat
。我不明白你为什么想+?
在这里使用,而你可能想使用\.dat
.我猜您可能还想确保整个文件名匹配,以便类似的内容foobarfoobarfoobarA1_2001_pm23aD.datfoobarfooabr
也被删除。如果是这样,请改用其中之一:
perl -le 'unlink(grep(!/^[0-9A-Z]{1,2}_\d{4}_\w+\.dat$/,@ARGV))' *
或者
for f in *; do
[[ "$f" =~ ^[0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat$ ]] || rm "$f";
done
最后,要删除目录,您可以执行以下操作:
for f in *; do
[[ "$f" =~ ^[0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat$ ]] || rm -rf "$f";
done
答案3
你可以这样做find
:
find . -regextype posix-extended \
-type f ! -regex '.*/[0-9A-Z]{1,2}_[[:digit:]]{4}_[[:alnum:]_]+?\.dat' -delete
- 当然,您可以将其全部放在一行中(删除
\
第一行末尾的 )。 -regextype posix-egrep
似乎工作完全一样好-regextype posix-extended
。- 如果您的版本
find
不支持-delete
,请使用-exec rm -- {} +
或-exec rm -- {} ';'
。 - 如果您只想搜索顶级目录,请使用
-maxdepth 1
.