通过正则表达式删除文件

通过正则表达式删除文件

我想保留名称匹配的文件[0-9A-Z]{1,2}_\d{4}_\w+?\.dat,例如,A1_2001_pm23aD.datK_1998_12.dat,并删除其余文件。

但是,lsrm命令不支持此类正则表达式。我怎样才能做到这一点?

答案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.

相关内容