Удаление файлов с помощью регулярного выражения

Я хочу сохранить файлы, имена которых соответствуют [0-9A-Z]{1,2}_\d{4}_\w+?\.dat A1_2001_pm23aD.dat , например, A1_2001_pm23aD.dat , K_1998_12.dat , и удалить остальные.

Однако команды ls и rm не поддерживают такие регулярные выражения. Как я могу это сделать?

  • исходный файл в качестве аргумента?
  • Почему некоторые команды не загружают пользовательскую среду при выполнении с помощью ssh? (в то время как другие делают)
  • Awk: печать последних N столбцов, где N передается через переменную
  • Набор результатов запроса Mysql в сценарии bash
  • Я попадаю в состояние гонки в bash?
  • Использовать awk интерактивно через трубу
  • Как найти md5sum файлов на удаленных машинах, выполнив ssh?
  • Sh Script с использованием ftp для размещения списка файлов
  • 3 Solutions collect form web for “Удаление файлов с помощью регулярного выражения”

    Использование расширенных шаров:

     shopt -s extglob printf '%s\n' !([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat) 

    это будет печатать все имена файлов / каталогов, которые не соответствуют ( ! ), соответствуют [[:digit:][:upper:]] за которыми следует ноль или один [[:digit:][:upper:]] а затем 4 [[:digit:]] между _ s и затем одним или несколькими [[: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$' 

    Есть много способов сделать это. Вы можете использовать язык сценариев, который понимает регулярные выражения. Например, в 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 , так что такие вещи, как 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 

    Вы можете сделать это с помощью 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 .
    Linux и Unix - лучшая ОС в мире.