- Лисаков и макромир
- Общий вид
- Пример №1
- xargs
- Пример №2
- xargs
- Пример №3
- Поиск в Linux с помощью команды find
- Общий синтаксис
- Описание опций
- Примеры использования find
- Поиск файла по имени
- Поиск по дате
- По типу
- Поиск по правам доступа
- Поиск файла по содержимому
- С сортировкой по дате модификации
- Лимит на количество выводимых результатов
- Поиск с действием (exec)
- Чистка по расписанию
- Как получить команду find и rename для работы с подкаталогами?
Лисаков и макромир
Данное сообщение не претендует на оригинальность, это просто очередной пример того, как можно переименовать много файлов с помощью командной строки в Linux, используя find , sed , xargs и mv .
Общий вид
- Вывести имена нужных файлов ( ls , echo или find ).
- Произвести замену каждого имени и вывести старое имя и новое имя ( sed ).
- Применить к каждой паре старое имя – новое имя команду mv ( xargs ).
На языке bash эти 3 команды могут выглядеть так:
Мы будем говорить о последнем варианте, поскольку find является очень мощной и гибкой утилитой для поиска файлов.
Пример №1
Простейший случай, необходимо произвести такую замену с большим количеством файлов:
Для экспериментов создадим директорию
Теперь в директории
/test/ должно появиться 5 пронумерованных файлов. Выведем эти файлы (точка после find означает, что поиск надо проводить в текущей директории; ключ -type f просит выводить только файлы).
Потоковый редактор sed в команде find | sed получает поток названий файлов от find. И с каждым названием файла он может делать какую-то операцию. Нас интересует замена, общий вид которой в sed выглядит так.
Общий вид команд в редакторе sed:
Если выполнить данные команды, то sed будет ждать ввода аргументов с клавиатуры. После каждого нажатия Enter sed выведет строку, заменив в ней ‘old’ на ‘new’, если ‘old’ будет присутствовать в введённой строке. Но обычно sed используется либо в связках типа find | sed , либо принимает в качестве аргумента имена файлов, чтобы произвести замены внутри файлов.
Заметьте, что вы сами можете выбирать разделитель — например, / , # или : (хотя можно использовать почти любой символ), комбинировать их нельзя. Буква ‘s’ — заменить (от англ. substitute); буква ‘g’ (от англ. global) в конце стоит для того, чтобы замена происходила во всей строке не только для первого вхождения, а столько раз, сколько там встретится «old». Когда в заменяемых выражениях встречаются слэши ( / или \ ), то каждую из них приходится предварять дополнительным обратным слэшем, тогда код слишком сильно напоминает частокол и удобнее использовать двоеточие или что-то другое в качестве разделителя.
Итак, посмотрим, что мы можем сделать двумя первыми шагами find | sed :
Отлично, нужные нам имена выведены. Но в третьем шаге утилите xargs нужны и старое, и новое имя файла, чтобы применить к ним команду mv . Поэтому модифицируем команду sed :
Знак «p;» (p — print), стоящий перед «s», просит sed выдавать не только результат, но и исходный материал. Теперь вывод будет такой:
То, что нужно. Переходим к третьему шагу.
xargs
Программа xargs работает с потоками данных. Утилита принимает один поток и может «распараллелить» его на несколько. Чтобы было лучше понятно, посмотрите простые примеры:
Для переименования файлов, очевидно, нам нужен ключик -n2 , тогда xargs разделит поток из старых и новых имён в две колонки.
Отлично. Осталось перед каждой парой вставить mv , и переименование произойдёт. Выполняем:
Вывода никакого не последует, но переименование произошло. Чтобы быть уверенным в результате, можно произвести проверку перед выполнением этой команды. Для этого надо добавить ключ -p к xargs . Тогда утилита будет показывать, что она сделала бы без ключа -p . Можно нажимать Enter и просматривать, что собирается сделать команда. Изменения применены не будут.
Если результаты устраивают, то нужно убрать ключ -p и повторить команду.
Пример №2
В директориях dir1/subdir1/ , dir1/subdir2/ ,… dir5/subdir5/ лежат файлы filename.txt. Нужно вытащить их оттуда, но уже с разными именами.
При необходимости создадим и очистим нашу экспериментальную директорию
/test/ и создадим там необходимую структуру файлов:
Итак, у нас получилось 25 файлов filename.txt в директориях dir1/subdir1/ , dir1/subdir2 ,… dir5/subdir5/ .
Выведем эти файлы. В этом случае -type f тоже сработал бы, но воспользуемся для разнообразия поиском по имени. Также используем звёздочку вместо точки, чтобы избавиться от ведущего ./ в выводе.
Попросим sed заменить все слэши на дефисы.
xargs
Убедившись, что всё произойдёт правильно, убираем ключ -p и повторяем команду.
Пример №3
В директории лежат файлы, пронумерованные от 0 до 1001. Если их выводить командой ls , они будут отсортированы по имени не так, как этого хотелось бы [1] . Добавим необходимое количество нулей в названия файлов.
При необходимости создаём тестовую директорию и/или чистим её и создаём наши 1001 файл:
Можно действовать так (не лучший вариант).
Первая команда всем файлам, начинающимся с одной цифры, добавит 3 нуля. Вторая команда всем файлам, начинающимся с двух цифр, добавит 2 нуля. Третья команда всем файлам, начинающимся с трёх цифр, добавит 1 ноль.
Здесь использованы регулярные выражения в sed . Разберём конструкцию
- ^ означает, что нужно искать с начала имени
- конструкция \(. \) позволяет заключённое в неё использовать как \1 в шаблоне замены
- 752 означает три любые цифры подряд.
- — — просто дефис.
- f — файл;
- d — каталог;
- l — ссылка;
- p — pipe;
- s — сокет.
- find находит соответствующий каталог ./Test 02 .
- find выполняет команду rename в этом каталоге.
- rename переименовывает Test 02 в Test_02 .
- find пытается спуститься в каталог Test 02 . Но этого больше нет.
В принципе, с этим можно справиться командой ls -v (natural sorting: 10 будет выведено после 9, а не после единицы), но мы всё-таки для упражнения произведём переименование. ↩︎
Источник
Поиск в Linux с помощью команды find
Утилита find представляет универсальный и функциональный способ для поиска в Linux. Данная статья является шпаргалкой с описанием и примерами ее использования.
Общий синтаксис
— путь к корневому каталогу, откуда начинать поиск. Например, find /home/user — искать в соответствующем каталоге. Для текущего каталога нужно использовать точку «.».
— набор правил, по которым выполнять поиск.
* по умолчанию, поиск рекурсивный. Для поиска в конкретном каталоге можно использовать опцию maxdepth.
Описание опций
Опция | Описание |
---|---|
-name | Поиск по имени. |
-iname | Регистронезависимый поиск по имени. |
-type | |
-size | Размер объекта. Задается в блоках по 512 байт или просто в байтах (с символом «c»). |
-mtime | Время изменения файла. Указывается в днях. |
-mmin | Время изменения в минутах. |
-atime | Время последнего обращения к объекту в днях. |
-amin | Время последнего обращения в минутах. |
-ctime | Последнее изменение владельца или прав на объект в днях. |
-cmin | Последнее изменение владельца или прав в минутах. |
-user | Поиск по владельцу. |
-group | По группе. |
-perm | С определенными правами доступа. |
-depth | Поиск должен начаться не с корня, а с самого глубоко вложенного каталога. |
-maxdepth | Максимальная глубина поиска по каталогам. -maxdepth 0 — поиск только в текущем каталоге. По умолчанию, поиск рекурсивный. |
-prune | Исключение перечисленных каталогов. |
-mount | Не переходить в другие файловые системы. |
-regex | По имени с регулярным выражением. |
-regextype | Тип регулярного выражения. |
-L или -follow | Показывает содержимое символьных ссылок (симлинк). |
-empty | Искать пустые каталоги. |
-delete | Удалить найденное. |
-ls | Вывод как ls -dgils |
Показать найденное. | |
-print0 | Путь к найденным объектам. |
-exec <> \; | Выполнить команду над найденным. |
-ok | Выдать запрос перед выполнением -exec. |
Также доступны логические операторы:
Оператор | Описание |
---|---|
-a | Логическое И. Объединяем несколько критериев поиска. |
-o | Логическое ИЛИ. Позволяем команде find выполнить поиск на основе одного из критериев поиска. |
-not или ! | Логическое НЕ. Инвертирует критерий поиска. |
Полный набор актуальных опций можно получить командой man find.
Примеры использования find
Поиск файла по имени
1. Простой поиск по имени:
find / -name «file.txt»
* в данном примере будет выполнен поиск файла с именем file.txt по всей файловой системе, начинающейся с корня /.
2. Поиск файла по части имени:
* данной командой будет выполнен поиск всех папок или файлов в корневой директории /, заканчивающихся на .tmp
3. Несколько условий.
а) Логическое И. Например, файлы, которые начинаются на sess_ и заканчиваются на cd:
find . -name «sess_*» -a -name «*cd»
б) Логическое ИЛИ. Например, файлы, которые начинаются на sess_ или заканчиваются на cd:
find . -name «sess_*» -o -name «*cd»
в) Более компактный вид имеют регулярные выражения, например:
find . -regex ‘.*/\(sess_.*cd\)’
* где в первом поиске применяется выражение, аналогичное примеру а), а во втором — б).
4. Найти все файлы, кроме .log:
find . ! -name «*.log»
* в данном примере мы воспользовались логическим оператором !.
Поиск по дате
1. Поиск файлов, которые менялись определенное количество дней назад:
find . -type f -mtime +60
* данная команда найдет файлы, которые менялись более 60 дней назад.
2. Поиск файлов с помощью newer. Данная опция доступна с версии 4.3.3 (посмотреть можно командой find —version).
а) дате изменения:
find . -type f -newermt «2019-11-02 00:00»
* покажет все файлы, которые менялись, начиная с 02.11.2019 00:00.
find . -type f -newermt 2019-10-31 ! -newermt 2019-11-02
* найдет все файлы, которые менялись в промежутке между 31.10.2019 и 01.11.2019 (включительно).
б) дате обращения:
find . -type f -newerat 2019-10-08
* все файлы, к которым обращались с 08.10.2019.
find . -type f -newerat 2019-10-01 ! -newerat 2019-11-01
* все файлы, к которым обращались в октябре.
в) дате создания:
find . -type f -newerct 2019-09-07
* все файлы, созданные с 07 сентября 2019 года.
find . -type f -newerct 2019-09-07 ! -newerct «2019-09-09 07:50:00»
* файлы, созданные с 07.09.2019 00:00:00 по 09.09.2019 07:50
По типу
Искать в текущей директории и всех ее подпапках только файлы:
* f — искать только файлы.
Поиск по правам доступа
1. Ищем все справами на чтение и запись:
find / -perm 0666
2. Находим файлы, доступ к которым имеет только владелец:
find / -perm 0600
Поиск файла по содержимому
find / -type f -exec grep -i -H «content» <> \;
* в данном примере выполнен рекурсивный поиск всех файлов в директории / и выведен список тех, в которых содержится строка content.
С сортировкой по дате модификации
find /data -type f -printf ‘%TY-%Tm-%Td %TT %p\n’ | sort -r
* команда найдет все файлы в каталоге /data, добавит к имени дату модификации и отсортирует данные по имени. В итоге получаем, что файлы будут идти в порядке их изменения.
Лимит на количество выводимых результатов
Самый распространенный пример — вывести один файл, который последний раз был модифицирован. Берем пример с сортировкой и добавляем следующее:
find /data -type f -printf ‘%TY-%Tm-%Td %TT %p\n’ | sort -r | head -n 1
Поиск с действием (exec)
1. Найти только файлы, которые начинаются на sess_ и удалить их:
find . -name «sess_*» -type f -print -exec rm <> \;
* -print использовать не обязательно, но он покажет все, что будет удаляться, поэтому данную опцию удобно использовать, когда команда выполняется вручную.
2. Переименовать найденные файлы:
find . -name «sess_*» -type f -exec mv <> new_name \;
find . -name «sess_*» -type f | xargs -I ‘<>‘ mv <> new_name
3. Вывести на экран количество найденных файлов и папок, которые заканчиваются на .tmp:
find . -name «*.tmp» | wc -l
4. Изменить права:
find /home/user/* -type d -exec chmod 2700 <> \;
* в данном примере мы ищем все каталоги (type d) в директории /home/user и ставим для них права 2700.
5. Передать найденные файлы конвееру (pipe):
find /etc -name ‘*.conf’ -follow -type f -exec cat <> \; | grep ‘test’
* в данном примере мы использовали find для поиска строки test в файлах, которые находятся в каталоге /etc, и название которых заканчивается на .conf. Для этого мы передали список найденных файлов команде grep, которая уже и выполнила поиск по содержимому данных файлов.
6. Произвести замену в файлах с помощью команды sed:
find /opt/project -type f -exec sed -i -e «s/test/production/g» <> \;
* находим все файлы в каталоге /opt/project и меняем их содержимое с test на production.
Чистка по расписанию
Команду find удобно использовать для автоматического удаления устаревших файлов.
Открываем на редактирование задания cron:
0 0 * * * /bin/find /tmp -mtime +14 -exec rm <> \;
* в данном примере мы удаляем все файлы и папки из каталога /tmp, которые старше 14 дней. Задание запускается каждый день в 00:00.
* полный путь к исполняемому файлу find смотрим командой which find — в разных UNIX системах он может располагаться в разных местах.
Источник
Как получить команду find и rename для работы с подкаталогами?
Возможный дубликат:
Рекурсивные файлы и каталоги переименования
У меня есть большой каталог музыкальных файлов, которые часто меняются, когда файлы и каталоги приходят и уходят. Мое предпочтение состоит в том, чтобы убедиться, что имена файлов и каталогов не содержат пробелов, поэтому я заменяю их символами подчеркивания.
Я захожу в основной каталог и запускаю эту команду:
Проблема в том, что когда есть подкаталоги, эта команда, кажется, теряется и возвращает ошибки. Поэтому, если у меня есть следующая структура каталогов:
… и если я запустил команду, то получаю следующие ошибки:
И тогда результат заключается в том, что моя структура каталогов выглядит так. Обратите внимание, что в подкаталогах по-прежнему есть пробелы:
Если я снова запустил команду, я получу эти ошибки, хотя кажется, что, возможно, она переименовала указанные каталоги:
Наконец, я запускаю команду еще один раз, и у меня нет ошибок, и у меня есть все каталоги и подкаталоги, названные так, как я хочу:
Очевидно, что это требует выполнения команды еще больше раз, когда у меня есть несколько подкаталогов, которые могут стать утомительными.
Как я могу сделать так, чтобы эта команда запускалась только один раз, и она будет переименовывать все каталоги и подкаталоги за один раз?
Моя конечная цель – включить это в сценарий Bash, чтобы я мог запускать его вместе с другими подобными командами, поэтому мне нужно, чтобы они не возвращали ошибки или не нуждались в большем количестве ввода от меня. Кроме того, я запускаю Ubuntu 12.04, если это имеет значение.
Вот что происходит:
Самый простой способ решить эту проблему – сказать, что find для работы наоборот: сначала найдите совпадения внутри каталога, а затем проверьте, совпадает ли сама директория. Это то, что -depth опция -depth .
Если вы добавите только -depth , вы -depth другой проблемой, которая заключается в том, что при find достигает Test 01/Test A , он вызывает rename ‘y/\ /\_/’ ‘Test 01/Test A’ , который пытается переименуйте этот каталог в Test_01/Test_A . Это не сработает, поскольку нет директории с именем Test_01 . -execdir исправление заключается в использовании опции -execdir , которая вызывает rename внутри каталога Test 01 и передает Test A в качестве аргумента. Вы можете ускорить процесс, передав несколько аргументов для rename в одну партию, используя + вместо ; для завершения команды -execdir .
Кроме того, используйте эту короткую, но загадочную команду zsh:
Функция zmv переименовывает файлы в соответствии с шаблонами. Исходный шаблон – **/* , который соответствует всем файлам ( * ) во всех подкаталогах рекурсивно ( **/ ). Квалификаторы glob (активированные параметром -Q ) указывают, что только каталоги сопоставлены ( / ), и эти точечные файлы включены ( D ). Параметр -w создает обратную ссылку для каждого шаблона шаблона источника. Замена начинается с $1 которая обозначает совпадение для первого шаблона (для ** , это включает в себя final / ), за которым следует $ <2>, который равен $2 (что соответствует * совпадению) для замены все пробельные символы _ . Добавьте опцию -v чтобы увидеть, что делает команда, вы заметите, что она сначала пересекает глубину, как find -depth .
Источник