Продолжаем удалять. [Re: Работа с «плохими» файлами в командной строке в Linux]

в 17:48, , рубрики: bash, linux, pattern matching, командная строка, Песочница, системное администрирование, файлы, метки: , , ,

Как известно, мир 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

Источник

Поделиться

* - обязательные к заполнению поля