Как известно, мир GNU/Linux многообразен. Для одной и той же задачи существует множество решений.
Порой один линуксоид решает проблему, а второй смотрит на данный процесс и испытывает неуемное желание вмешаться, сделать по-своему. В подобных условиях и была рождена эта запись.
Топик, в котором была затронута тема удаления файлов с неправильными именами находится здесь. Далее будут приведены иные методы решения той же задачи.
Под «правильным» файлом будем понимать файл с именем вида number.txt, под «неправильным» — все прочие.
Интерактивное удаление
Метод чрезвычайно удобен, если в директории находится небольшое количество файлов (либо можно выделить некое их подмножество с помощью wildcard), часть из которых нужно удалить.
Команда rm обладает опцией -i, которая запрашивает у пользователя подтверждение для удаления файла.
$ ls -lAh
-rw-r--r-- 1 user user 0 May 15 01:47 ?
-rw-r--r-- 1 user user 0 May 15 01:47 ?
-rw-r--r-- 1 user user 0 May 15 01:47 ?
-rw-r--r-- 1 user user 0 May 15 01:48 1.txt
-rw-r--r-- 1 user user 0 May 15 01:48 ?.txt
$ rm -i *
rm: remove regular empty file `n'? y
rm: remove regular empty file `v'? y
rm: remove regular empty file `f'? y
rm: remove regular empty file `1.txt'? n
rm: remove regular empty file `r.txt'? y
$ ls -lAh
-rw-r--r-- 1 user user 0 May 15 01:48 1.txt
Быстро и просто.
Отрицающий wildcard
Усложним задачу, создав 100 файлов с правильным названием и 100 неправильных:
$ touch {1..100}$'x0a'.txt
$ touch {1..100}.txt
$ ls -A
? 15?.txt 22?.txt 2?.txt 37?.txt 44?.txt 51?.txt 59?.txt 66?.txt 73?.txt 80?.txt 88?.txt 95?.txt
? 16.txt 23.txt 30.txt 38.txt 45.txt 52.txt 5.txt 67.txt 74.txt 81.txt 89.txt 96.txt
? 16?.txt 23?.txt 30?.txt 38?.txt 45?.txt 52?.txt 5?.txt 67?.txt 74?.txt 81?.txt 89?.txt 96?.txt
100.txt 17.txt 24.txt 31.txt 39.txt 46.txt 53.txt 60.txt 68.txt 75.txt 82.txt 8.txt 97.txt
100?.txt 17?.txt 24?.txt 31?.txt 39?.txt 46?.txt 53?.txt 60?.txt 68?.txt 75?.txt 82?.txt 8?.txt 97?.txt
10.txt 18.txt 25.txt 32.txt 3.txt 47.txt 54.txt 61.txt 69.txt 76.txt 83.txt 90.txt 98.txt
10?.txt 18?.txt 25?.txt 32?.txt 3?.txt 47?.txt 54?.txt 61?.txt 69?.txt 76?.txt 83?.txt 90?.txt 98?.txt
11.txt 19.txt 26.txt 33.txt 40.txt 48.txt 55.txt 62.txt 6.txt 77.txt 84.txt 91.txt 99.txt
11?.txt 19?.txt 26?.txt 33?.txt 40?.txt 48?.txt 55?.txt 62?.txt 6?.txt 77?.txt 84?.txt 91?.txt 99?.txt
12.txt 1.txt 27.txt 34.txt 41.txt 49.txt 56.txt 63.txt 70.txt 78.txt 85.txt 92.txt 9.txt
12?.txt 1?.txt 27?.txt 34?.txt 41?.txt 49?.txt 56?.txt 63?.txt 70?.txt 78?.txt 85?.txt 92?.txt 9?.txt
13.txt 20.txt 28.txt 35.txt 42.txt 4.txt 57.txt 64.txt 71.txt 79.txt 86.txt 93.txt ?.txt
13?.txt 20?.txt 28?.txt 35?.txt 42?.txt 4?.txt 57?.txt 64?.txt 71?.txt 79?.txt 86?.txt 93?.txt
14.txt 21.txt 29.txt 36.txt 43.txt 50.txt 58.txt 65.txt 72.txt 7.txt 87.txt 94.txt
14?.txt 21?.txt 29?.txt 36?.txt 43?.txt 50?.txt 58?.txt 65?.txt 72?.txt 7?.txt 87?.txt 94?.txt
15.txt 22.txt 2.txt 37.txt 44.txt 51.txt 59.txt 66.txt 73.txt 80.txt 88.txt 95.txt
Случай немного надуманный, но позволяет показать новый метод. Предполагая, что нам нужны файлы вида number.txt, с помощью отрицающего wildcard выбираем, что удалить:
$ ls *[!0-9].txt
100?.txt 17?.txt 24?.txt 31?.txt 39?.txt 46?.txt 53?.txt 60?.txt 68?.txt 75?.txt 82?.txt 8?.txt 97?.txt
10?.txt 18?.txt 25?.txt 32?.txt 3?.txt 47?.txt 54?.txt 61?.txt 69?.txt 76?.txt 83?.txt 90?.txt 98?.txt
11?.txt 19?.txt 26?.txt 33?.txt 40?.txt 48?.txt 55?.txt 62?.txt 6?.txt 77?.txt 84?.txt 91?.txt 99?.txt
12?.txt 1?.txt 27?.txt 34?.txt 41?.txt 49?.txt 56?.txt 63?.txt 70?.txt 78?.txt 85?.txt 92?.txt 9?.txt
13?.txt 20?.txt 28?.txt 35?.txt 42?.txt 4?.txt 57?.txt 64?.txt 71?.txt 79?.txt 86?.txt 93?.txt ?.txt
14?.txt 21?.txt 29?.txt 36?.txt 43?.txt 50?.txt 58?.txt 65?.txt 72?.txt 7?.txt 87?.txt 94?.txt
15?.txt 22?.txt 2?.txt 37?.txt 44?.txt 51?.txt 59?.txt 66?.txt 73?.txt 80?.txt 88?.txt 95?.txt
16?.txt 23?.txt 30?.txt 38?.txt 45?.txt 52?.txt 5?.txt 67?.txt 74?.txt 81?.txt 89?.txt 96?.txt
Убедившись, что всё в порядке, удаляем эти файлы.
$ rm *[!0-9].txt
find
Внимательный читатель вероятно заметил, что в предыдущем примере я пропустил 3 неправильных файла. Исправлюсь.
В директории находится 100 файлов вида number.txt и 3 файла с неким непонятным названием.
Одним из методов выделения ненужных нам файлов является find в связке с xargs (старый добрый обычай бородатых администраторов *nix связывать утилиты через pipe)
$ find . -type f -not -name '*txt'
./?
./?
./?
$ find . -type f -not -name '*.txt' | xargs rm
rm: cannot remove `./': Is a directory
Хм, какой-то из файлов оказался назойливым.
% ls -A
? 15.txt 21.txt 28.txt 34.txt 40.txt 47.txt 53.txt 5.txt 66.txt 72.txt 79.txt 85.txt 91.txt 98.txt
100.txt 16.txt 22.txt 29.txt 35.txt 41.txt 48.txt 54.txt 60.txt 67.txt 73.txt 7.txt 86.txt 92.txt 99.txt
10.txt 17.txt 23.txt 2.txt 36.txt 42.txt 49.txt 55.txt 61.txt 68.txt 74.txt 80.txt 87.txt 93.txt 9.txt
11.txt 18.txt 24.txt 30.txt 37.txt 43.txt 4.txt 56.txt 62.txt 69.txt 75.txt 81.txt 88.txt 94.txt
12.txt 19.txt 25.txt 31.txt 38.txt 44.txt 50.txt 57.txt 63.txt 6.txt 76.txt 82.txt 89.txt 95.txt
13.txt 1.txt 26.txt 32.txt 39.txt 45.txt 51.txt 58.txt 64.txt 70.txt 77.txt 83.txt 8.txt 96.txt
14.txt 20.txt 27.txt 33.txt 3.txt 46.txt 52.txt 59.txt 65.txt 71.txt 78.txt 84.txt 90.txt 97.txt
Как видим, он единственный.
extglob
Bash имеет множество опций. Нас интересует extglob — использование расширенных возможностей сравнения с образцом(pattern matching).
$ shopt extglob
extglob off
$ shopt -s extglob
$ shopt extglob
extglob on
После включения опции пользователю становится (в частности) доступна возможность применения «отрицающего wildcard», действующего целиком на список образцов:
$ ls !(*.txt)
?
$ rm !(*.txt)
$ ls * | wc
100 100 692
Осталось 100 правильных файлов, успех!
Отключаем extglob, если он больше не нужен:
$ shopt -u extglob
Спасибо за внимание.
Использованные материалы:
man rm
man bash
man find
Автор: JIghtuse