Как я могу удалить пронумерованные файлы в заданном диапазоне?

16

У меня folderAесть некоторые файлы с последовательностью номеров, начиная с a_000000. Что я хочу сделать, это удалить файлы, начиная с определенного числа: скажем, a_000750до конца файлов в этом folderA. Может кто-нибудь, пожалуйста, посоветуйте, как это сделать с помощью сценария оболочки?

Tak
источник
Могу ли я предположить, что все эти имена имеют 6-значные суффиксы?
Муру
да, они есть :) они начинаются с a_000000 до некоторого числа
Так
5
rm a_000[89]* a_0007[5-9]*?
Rinzwind
@Rinzwind Не могли бы вы объяснить эту команду?
Так
2
@ user1460166 a_000[89]*включает каждый файл, начинающийся с a_0008или a_0009, и a_0007[5-9]*включает каждый файл, начинающийся с, a_0007а затем содержащий число от 5 до 9, за которым следует что-либо.
Муру

Ответы:

35

Предполагая, что вы знаете или можете угадать конец диапазона, вы можете использовать скобки :

rm a_{000750..000850}

Приведенное выше удалит 101 файл в диапазоне от a_000750 до a_000850 включительно (и пожалуется на имена файлов, которые ссылаются на несуществующие файлы). Если у вас слишком много файлов для этого, используйте find:

find . -name 'a_*' | while read file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Здесь findпросто перечислены все файлы, соответствующие a_*. Список передается в whileцикл, где каждое имя файла считывается в переменную $file. Затем, используя возможности bash для работы со строками , если числовая часть (find печатает файлы как ./file, а значит ${file#./a_}печатает только номер) 000750больше или больше, файл удаляется. Это -vпросто там, чтобы вы могли видеть, какие файлы были удалены.

Обратите внимание, что приведенное выше предполагает нормальные имена файлов. Если ваши имена могут содержать пробелы, символы новой строки или другие странные символы, используйте вместо этого:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done
terdon
источник
Зачем избегать [[?
Муру
1
@muru зачем его использовать? например, [[здесь ничего не упрощается [[ "${file#./a_}" > 000749 ]], даже не сокращается. Мне не нравится использовать ненужный синтаксис, и он будет работать даже в таких простых оболочках, как dash.
Тердон
Потому что [[лучше справляется с пробелами и странностями (меня это тоже не волнует >).
Муру
1
@muru да, но [хорошо, если вы процитируете переменную, как у меня, работает на гораздо больше оболочек и проще.
Тердон
Если вы настаиваете. Не моя проблема.
Муру
3

Вы могли бы сделать что-то вроде этого:

find . -regextype posix-extended -iregex './a_[0-9]{6}' -execdir bash -c '[[ ${1##./a_} > 000750 ]] && echo $1' "removing: " {} \;

Или:

find . -regextype posix-extended -iregex './a_[0-9]{6}' | sort | sed '0,/000750/d' | xargs echo

Первый метод предполагает фиксированный префикс, удаляет его и проверяет значение.

Второй метод предполагает использование суффикса фиксированной длины (и общего фиксированного префикса) и опирается на этот факт; и что, хотя и 201идет раньше 31в лексикографическом смысле, это не раньше 031.

Проверьте это с помощью echoкоманды, и как только вы убедитесь, что она перечисляет правильные файлы, используйте rmвместо этого.

Мур
источник
никто из них не работает: /
Так
@ user1460166 Ах, это, вероятно, из-за соответствия регулярному выражению. Я обновлю это.
Муру
до сих пор не работает. Кстати, файлы .png :)
Так
@ user1460166 можешь сказать как оно не работает?
Муру
Я открываю терминал, cd в папку, затем копирую вашу строку и вставляю ее, но файлы не удаляются
Tak
0

Оболочка POSIX

Первое решение terdon основано на расширении скобок, которое является свойством bashи ksh, однако, его нельзя использовать в стандартной /bin/shоболочке, на которую в Ubuntu есть символическая ссылка /bin/dash.

В тех случаях, когда вам приходится полагаться /bin/shна переносимость ваших сценариев, обычно есть два подхода к этому. Можно было бы с помощью болтовни. Просто cd folderAи оттуда беги rm a_*. Другой способ - реализовать C-стиль для альтернативы цикла с использованием while <CONDITION>;do ...doneязыка оболочки и отформатировать числа с помощью printf:

$ sh -c 'i=0;while [ $i -le 750 ]; do filename=$(printf "a_%06d" $i);echo "$filename";i=$((i+1)) ;done'

Обратите внимание, что здесь я использую echo. Замените echo "$filename"на rm ./"$filename"или rm -- "$filename"когда вы будете готовы удалить файлы. Также обратите внимание, что это должно быть выполнено, когда вы уже cdзашли в нужный каталог.

(ab) используя awk

Awk, являющийся хорошим C-подобным языком, может помочь нам двумя способами: (1) мы можем сгенерировать имена файлов с помощью for-loop и отформатировать их с помощью sprintfфункции, и (2) удалить указанные файлы с помощью system()команды, которая передаст наше сгенерированное имя файла и rmкоманду к /bin/sh:

awk 'BEGIN{for(i=0;i<=750;i++){filename=sprintf("a_%06d",i);system("rm "filename);} }'

Perl

Продолжая идею переносимого подхода, где мы «генерируем» имена файлов, мы можем сделать то же самое в Perl:

perl -le 'for(0..750){$fd=sprintf("a_%06d",$_);unlink($fd)}'
Сергей Колодяжный
источник
0

Так просто как

rm partialfilename* -f

В вашем примере это

rm a_00075* -f
Виталий Дубина
источник
1
Извините, но это не диапазон, все эти файлы начинаются с a_00075...
Fabby
1
* подстановочный знак, OP ищет ответ о том, как удалить ДИАПАЗОН вещей ... например, если у вас были файлы с 1 по 100, и вы хотели удалить с 41 по 75
Джошуа Беснеатте