В этом параграфе мы научимся находить файлы и информацию внутри них.
Мы разберём, как использовать find для поиска по имени и типу файла, как применять grep для поиска текста, чем шаблоны glob отличаются от регулярных выражений и как с помощью wc подсчитывать строки, слова и символы.
Эти приёмы помогут быстро ориентироваться в системе и анализировать большие объёмы данных.
Ключевые вопросы параграфа
- Как искать файлы по имени, типу или шаблону?
- Как искать текст внутри файлов?
- Что такое регулярные выражения и чем они отличаются от шаблонов glob?
- Как подсчитать количество строк, слов и символов?
- Как сравнить два файла или даже два каталога?
Поиск файлов с помощью find
В предыдущем параграфе мы научились просматривать содержимое файлов при помощи команд cat и less, указывая имя файла в качестве аргумента.
Но что, если мы не знаем точное имя файла, а их десятки или сотни в каталоге? Мы можем получить вывод каталога командой ls, но найти конкретный файл в большом списке всё ещё будет задачей на внимательность. На помощь нам придёт команда find.
Команда find выполняет поиск файлов и каталогов по множеству критериев: по имени, типу, дате изменения, размеру и многим другим.
find обходит весь указанный каталог и все вложенные в него файлы, поэтому отлично подходит для поиска не только по конкретному каталогу, но и по всей файловой системе.
Базовый формат команды прост:
1find <путь> <условия> [действие]
И самый простой пример — поиск всех файлов с именем report.txt в текущем каталоге — будет выглядеть так:
1alice@ubuntu:~$ find . -name "report.txt"
2./Documents/report.txt
Разберём переданные опции:
.— текущий каталог (начальная точка поиска);-name— условие поиска по имени;"report.txt"— точное имя файла.
Мы указали имя файла и текущий каталог для поиска и нашли совпадение в каталоге ./Documents.
Но что, если нужно искать не конкретное имя? Мы можем использовать шаблоны glob, например *:
1alice@ubuntu:~$ find . -name "*.log"
2./Documents/app.log
3./Backup/test-1.log
4./Backup/test-2.log
5./hello.log
Данной командой мы найдём все файлы, имя которых оканчивается на .log в текущем каталоге (и даже в его подкаталогах).
Поиск по типу и другим свойствам
Поиск по имени — это лишь один из сценариев. find умеет находить объекты по их типу, времени изменения, размеру и другим параметрам.
Поиск по типу
1alice@ubuntu:~$ find . -type d # найти все каталоги
2alice@ubuntu:~$ find . -type f # найти все обычные файлы
3alice@ubuntu:~$ find . -type l # найти все символьные ссылки
Поиск по дате изменения (mtime)
1alice@ubuntu:~$ find . -mtime -1 # изменённые за последние сутки
2alice@ubuntu:~$ find . -mtime +7 # старше недели
У mtime интересный формат: цифры -1 и 7 здесь означают, сколько полных 24-часовых периодов прошло с момента последнего изменения файла.
Здесь знак перед числом тоже имеет своё значение:
-N— меньшеNдней,N— ровноNдней,+N— большеNдней.
|
Формат |
Что означает |
Пример |
|
|
Изменён в течение последних 24 часов |
Файлы, изменённые сегодня |
|
|
Изменён менее чем 1 день назад |
Файлы, изменённые за последние 24 часа |
|
|
Изменён от 24 до 48 часов назад |
Файлы, изменённые вчера |
|
|
Изменён более чем 7 дней назад |
Файлы старше недели |
Помимо времени последнего изменения (mtime), find может искать по времени последнего чтения файла (atime) и времени изменения метаданных (ctime).
Тут советуем сделать паузу и вспомнить, как смотреть временные метки файла при помощи команды stat.
Поиск по размеру файла
1alice@ubuntu:~$ find . -size +100M # файлы больше 100 МБ
Здесь действует тот же принцип, что и для поиска по времени изменения.
Мы указываем нужный знак и размер файла с единицей измерения:
-100M— меньше 100 МБ,100M— ровно 100 МБ,+100M— больше 100 МБ.
Помимо мегабайтов (M), мы можем использовать и другие единицы:
|
Суффикс |
Единица |
Пример |
Что означает |
|
c |
Байты |
|
Больше 100 Б |
|
k |
Килобайты (1024 Б) |
|
Меньше 10 КБ |
|
M |
Мегабайты (1024² Б) |
|
Больше 100 МБ |
|
G |
Гигабайты (1024³ Б) |
|
Больше 1 ГБ |
|
b |
Блоки по 512 Б (по умолчанию) |
|
Ровно 4 блока (2 КБ) |
Поиск по размеру и времени часто используют администраторы для анализа логов и очистки системы от временных файлов.
1alice@ubuntu:~$ find /tmp -size +1M -mtime +3 -delete
Эта команда найдёт временные файлы старше трёх дней и больше 1 МБ в каталоге /tmp и сразу же удалит встроенным действием -delete. Об этом — дальше.
Выполнение действий над найденными файлами
find умеет не только находить, но и делать что-то с результатами.
Давайте рассмотрим подробнее, какие действия нам доступны.
Удаление
-delete удаляет найденные объекты встроенными силами find — быстро и «тихо».
Подходит для файлов и пустых каталогов.
1alice@ubuntu:~$ find . -type f -name '*.tmp' -mtime +7 -delete
Важно: фильтры (-type, -name, -mtime, -size и т. п.) нужно ставить до -delete.
-delete очень удобен и не требует дополнительных усилий для написания команды удаления, но имеет ряд ограничений. Например, -delete не удаляет непустые каталоги.
Запуск команды над файлом
За это отвечают опции -exec и -ok. Разберём их по очереди.
exec может запускать команду над каждым найденным файлом (а точнее — путём), в том числе и команду rm для удаления.
У -exec есть две формы, про которые стоит знать:
-exec <команда> {} \;— запуск по одному пути за раз,-exec <команда> {} +— запуск реже, сразу пачкой путей (обычно быстрее),
где{}— место подстановки найденного пути.
Давайте разберём, в чём разница.
Допустим, в текущем каталоге есть несколько логов:
1alice@ubuntu:~$ ls
2app1.log app2.log app3.log
Давайте обработаем их при помощи формы -exec <команда> {} \;, по одному файлу за раз. Команда будет запущена столько раз, сколько файлов было найдено:
1alice@ubuntu:~$ find . -name '*.log' -exec echo "Обработка:" {} \;
2Обработка: ./app1.log
3Обработка: ./app2.log
4Обработка: ./app3.log
Для тестового прогона find -exec можно безопасно использовать команду echo.
Обратите внимание: echo в итоге вызвался три раза, по одному на каждый найденный .log-файл.
Эта форма работает медленнее, но зато поддерживает работу с командами, которые не умеют принимать несколько аргументов.
Теперь обработаем их через форму -exec <команда> {} +. Все найденные пути будут переданы команде одним списком — команда в итоге будет вызываться реже:
1alice@ubuntu:~$ find . -name '*.log' -exec echo "Обработка:" {} +
2Обработка: ./app1.log ./app2.log ./app3.log
echo вызвался только один раз, но сразу с тремя аргументами.
Такой способ быстрее и лучше подходит для команд вроде rm, gzip, tar, ls.
Зафиксируем разницу:
|
Форма |
Что делает |
Когда использовать |
|
|
Запускает команду для каждого файла |
Когда команда не умеет принимать несколько аргументов |
|
|
Запускает команду один раз для списка |
Когда команда принимает несколько путей (быстрее) |
Теперь поговорим об -ok. На самом деле -ok делает то же, что и exec, но требует подтверждения перед каждым запуском.
Давайте посмотрим, как это выглядит, на нашем наборе логов:
1alice@ubuntu:~$ find . -name '*.log' -ok rm -- {} \;
2< rm ... ./app1.log > ? y
3< rm ... ./app2.log > ? n
4< rm ... ./app3.log > ? y
Что тут происходит:
findспрашивает перед каждым файлом —y(yes) илиn(no);- команда
rmвыполняется только для тех файлов, где вы ответилиy.
Важно: -ok не поддерживает форму с +, он всегда работает над одним файлом за раз, как -exec <команда> {} \;.
-ok специально сделан как интерактивный вариант -exec, и его смысл в том, чтобы задать пользователю вопрос для каждого найденного файла.
Мы можем использовать действие -ok для проверки, что всё отработало как надо. А после можно заменить на -exec «с плюсом» для ускорения и автоматизации.
Ограничение длины командной строки
Вы могли заметить и задать закономерный вопрос: а что будет, если мы запустим команду find . -name '*.log' -exec echo "Обработка:" {} + и найдём большое количество файлов? Как все эти файлы подставятся в качестве аргументов? Есть ли ограничение по длине или количеству аргументов?
Да, у системы действительно есть ограничение по общей длине аргументов при запуске процесса.
Это ограничение задаётся ядром Linux, и его можно посмотреть так:
1alice@ubuntu:~$ getconf ARG_MAX
22097152
В большинстве современных систем значение около 2 MБ (или 2097152 байта, как показано выше).
Это включает не только имена файлов, но и переменные окружения, пробелы и прочее.
find знает про это ограничение. Если файлов так много, что все пути не помещаются в один вызов, find автоматически разобьёт их на несколько вызовов команды, то есть find сам разделит список на подходящие по длине куски.
Форма -exec <команда> {} + безопасна в использовании, даже если найденных файлов миллионы. find гарантирует, что команда не превысит системный лимит аргументов.
Примеры использования
Пример 1. Если нам нужно удалить временные .tmp-файлы старше 7 дней, мы можем просто использовать опцию -delete:
1alice@ubuntu:~$ find . -type f -name '*.tmp' -mtime +7 -delete
Пример 2. Если нам нужно удалить все каталоги cache и сделать это без подтверждений — мы можем воспользоваться опцией -exec:
1alice@ubuntu:~$ find . -type d -name 'cache' -exec rm -rf {} +
Действие -delete не позволило бы нам такое удаление из-за наличия непустых каталогов.
Пример 3. Если мы хотим получать подтверждение для каждого найденного объекта, мы можем использовать опцию -ok:
1alice@ubuntu:~$ find . -type f -name "*.bak" -ok rm {} \;
Давайте проверим, как вы разобрались с поиском файлов:
Поиск текста в файлах с помощью grep
Давайте перейдём от поиска файлов к поиску внутри файлов.
Мы можем искать не только файлы по их именам, но и строки в тексте конкретного файла. Поможет нам в этом команда grep, с которой вы познакомились в предыдущем параграфе.
Это очень мощный инструмент для поиска по тексту, который часто используется в анализе логов, исходного кода, конфигураций приложений и просто больших текстовых файлов.
Базовый формат команды выглядит так:
1grep [опции] "шаблон" файл
И простейший пример поиска строк с ошибками в логе:
1alice@ubuntu:~$ grep "error" app.log
2Error: Hello this is error!
В результате выполнения grep мы получим вывод строк, в которых встречалось слово error.
По умолчанию поиск чувствителен к регистру, то есть Error, ERROR, и error — абсолютно разные слова с точки зрения grep.
Чтобы игнорировать регистр, используйте -i:
1alice@ubuntu:~$ grep -i "error" app.log
2Error: Hello this is error!
3ERROR: And this is another ERROR.
4Error: And another
Теперь мы получили все строки с error, независимо от регистра.
Опции grep
Помимо -i, есть и другие полезные опции:
|
Опция |
Что позволяет делать |
Пример |
|
|
Игнорировать регистр |
|
|
|
Показать номера строк |
|
|
|
Искать рекурсивно в каталогах |
|
|
|
Исключить строки с шаблоном |
|
|
|
Использовать расширенные регулярные выражения (подробнее далее) |
|
Например, мы можем получить не только содержание строки, но и её номер. Это поможет нам быстрее найти нужную строку в файле, если мы захотим её отредактировать:
1alice@ubuntu:~$ grep -in "error" app.log
21:Error: Hello this is error!
33:ERROR: And this is another ERROR.
412:Error: And another
Обратите внимание: теперь мы знаем, что совпадения для error есть в строках 1, 3 и 12.
Также мы можем исключить строки по шаблону -v, например, чтобы оставить все строки, кроме содержащих ERROR:
1alice@ubuntu:~$ grep -inv "error" app.log
22:INFO: Application started
34:WARNING: Low disk space
45:INFO: Retrying connection
56:WARNING: High memory usage detected
67:INFO: Application running normally
Использование grep
grep часто применяют с пайпами (|) для фильтрации вывода других программ.
Например, команда ps aux, которая выводит информацию о запущенных процессах, выводит достаточно большой список строк (мы даже передавали его в less в предыдущем параграфе для удобства).
Но если нас интересует информация только о конкретном процессе и мы знаем его имя — мы можем использовать команду grep, чтобы получить только нужные строки:
1alice@ubuntu:~$ ps aux | grep "sshd"
2root 973 0.0 0.3 12020 7936 ? Ss Oct11 0:22 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
3root 89128 0.0 0.5 14844 10112 ? Ss 07:42 0:00 sshd: alice [priv]
4alice 89212 0.0 0.3 15004 6808 ? S 07:42 0:00 sshd: alice@pts/1
5root 91388 0.0 0.5 14844 10112 ? Ss 09:59 0:00 sshd: alice [priv]
6alice 91472 0.0 0.3 15004 6808 ? S 09:59 0:00 sshd: alice@pts/0
7alice 91600 0.0 0.1 7076 2176 pts/0 S+ 10:09 0:00 grep --color=auto sshd
Давайте познакомимся ещё с одной полезной опцией — -E, которая позволяет использовать регулярные выражения.
Например, мы можем искать совпадения сразу по нескольким словам. Скажем, по слову FAIL и по слову ERROR:
1alice@ubuntu:~$ grep -Er "(ERROR|FAIL)" app.log
2ERROR: And this is another ERROR.
3FAIL: The system has failed.
Здесь (ERROR|FAIL) — регулярное выражение. Поговорим о них подробнее.
Регулярные выражения
Регулярные выражения (или regex, от англ. regular expressions) — это способ описать шаблон текста, который вы хотите найти.
Если glob-шаблоны вроде *.txt помогают искать имена файлов, то регулярные выражения позволяют искать содержимое.
С их помощью можно искать не только «где написано error», но и, например, «все строки, где встречается слово, начинающееся с заглавной буквы», или «все даты в формате 2025-10-16».
Регулярные выражения встречаются повсюду:
- в командах Linux —
grep,sed,awk,jq; - текстовых редакторах — VS Code, Vim, Sublime Text;
- языках программирования — Python, JavaScript, Go, Rust и других.
Проще говоря, регулярные выражения — это универсальный язык поиска по тексту.
Например, можно задать правило для поиска «всех строк, где в начале написано def» — и тем самым вы найдёте объявления функций в Python-коде.
Пара слов о новых Linux-командах
sedиawk— это мощные «комбайны» для работы с текстом, которые позволяют не только искать, но и заменять текст по очень гибким шаблонам.jq— позволяет работать с JSON-данными.JSON— это очень популярный формат структурированных данных, похожий на словари или объекты в языках программирования. JSON легко узнать по фигурным скобкам{}и кавычкам вокруг ключей и значений.
1{
2 "user": "alice",
3 "age": 28,
4 "active": true
5}
Примеры
|
Что ищем |
Шаблон |
Что найдёт |
|
Любое слово, начинающееся с |
|
Строки, где |
|
Любое число |
|
42, 1337, 2025 |
|
Адрес электронной почты |
|
|
|
Дату формата |
|
|
Давайте рассмотрим элементы, которые используются в шаблоне:
^— указывает, что мы ищем совпадение в начале строки;$— указывает, что мы ищем совпадение в конце строки;[]— задаёт диапазон символов, которые должны совпасть;{n}— задаёт количество символов, которые должны совпасть; количество символов можно указывать в виде диапазона, например:{2,}— два или более символа,{,3}— три или менее символа;
- + — одно или более вхождений;
\.— точка как символ, обратный слешу\, используется здесь для экранирования.
Пара слов о cимволах
По умолчанию в регулярных выражениях точка (.) — это специальный символ, который означает «любой одиночный символ, кроме символа перевода строки». Но чтобы найти настоящую точку (например, в адресе электронной почты example.com), нужно экранировать её обратным слешем (\).
В Linux \ называется escape-символом — он «снимает» специальное значение со следующего за ним символа, заставляя воспринимать его буквально. Этот процесс называется экранированием.
Эти элементы можно комбинировать, создавая достаточно сложные шаблоны, например:
^[A-Z].*[.!?]$ — найдёт строки, начинающиеся с заглавной буквы и заканчивающиеся точкой, восклицательным или вопросительным знаком.
Как построить регулярное выражение
Начнём с самого простого: найдём строки, где встречается слово error (в любом регистре):
1alice@ubuntu:~$ grep -Ei "error" app.log
А теперь — все строки, в начале которых есть слово Error (с заглавной буквы):
1alice@ubuntu:~$ grep -E "^Error" app.log
^ — означает «начало строки». То есть шаблон ^Error совпадёт только с теми строками, где Error идёт в самом начале.
Символы, из которых строятся выражения
Каждый символ в регулярном выражении — это правило. Можно комбинировать их, чтобы построить нужный шаблон.
|
Символ |
Что значит |
Пример |
Что найдёт |
|
|
Любой символ |
|
|
|
|
0 или больше повторений |
|
|
|
|
1 или больше повторений |
|
|
|
|
0 или 1 повторение |
|
|
|
|
Набор символов |
|
|
|
|
Количество повторений |
|
Четыре цифры подряд ( |
|
|
Количество повторений в диапазоне |
|
От одной до трёх цифр подряд ( |
|
|
Начало строки |
|
Строки, начинающиеся с |
|
|
Конец строки |
|
Строки, заканчивающиеся на |
|
|
Экранирование символа, следующего за слешем |
|
Строки, содержащие плюс и две буквы подряд ( |
|
|
Границы слова |
|
Слово |
Поиск года в тексте
Допустим, мы хотим найти в файле все строки, в которых встречается год: четыре цифры, первые две из которых — 20.
Давайте попробуем построить шаблон.
Для начала подумаем, какое правило стоит сформулировать:
- Мы можем начать с простого
2025. Это тоже шаблон, но под него подойдёт только один конкретный год. - Мы можем использовать
.в виде20.., тогда к этому шаблону подойдут годы вроде2024или2000, но также в него войдут и буквы:20aA, что нам не очень подходит. - Аналогичным образом откажемся от символов
*и+: они тоже включают буквы, плюс мы не уложимся в длину из четырёх цифр, характерных для года. - Самый близкий по смыслу шаблон здесь — это
[]. В нём мы можем описать, что именно мы хотим получить. Например, шаблон[0-9]включает любую цифру, но не буквы — то, что нам нужно!
То есть наш шаблон для поиска года, начинающегося с 20, будет выглядеть так:
120[0-9][0-9]
Очень неплохо! Но мы можем упростить его, указав количество повторений через {}. Мы знаем, что нам нужны ровно две цифры, подходящие под этот шаблон и расположенные одна за другой, поэтому мы можем использовать {2}:
120[0-9]{2}
Если мы хотим найти строки, которые будут начинаться с года или содержать год в конце, мы можем добавить символы ^ и $:
1^20[0-9]{2}
2# 2025 — отличный год для изучения Linux
120[0-9]{2}$
2# Отличный год для изучения Linux, 2025
Если мы хотим, чтобы строка начиналась с 2025 и заканчивалась на 2025 (то есть содержала только 2025), мы можем использовать оба символа:
1^20[0-9]{2}$
2# 2025
Мы ищем 2025 в любом месте строки, поэтому не будем использовать ^ и $. Давайте посмотрим, как наше выражение выглядит в итоге в команде grep:
1alice@ubuntu:~$ grep -E "20[0-9]{2}" report.txt
2Report for 2023
3Data updated on 2021-09-15
4Here is the data: 12013 lines of code in the lab
Идеально! Мы научились искать годы в тексте!
Но обратите внимание: под наш шаблон также попало число 12013.
Ничего страшного. Мы можем использовать границы слова \b, чтобы наш год всегда был целым словом, а не частью длинного числа
Наша итоговая команда с выражением будет выглядеть так:
1alice@ubuntu:~$ grep -E "\b20[0-9]{2}\b" report.txt
2Report for 2023
3Data updated on 2021-09-15
На первый взгляд, регулярные выражения могут казаться сложными — да и не на первый тоже. Поэтому советуем попрактиковаться в специальном тренажёре. В нём можно ввести текст и попробовать составить регулярное выражение, которое найдёт, например, все гласные буквы, или все согласные, или слова, начинающееся с «пре». В общем, проявите фантазию.
Регулярные выражения или glob-шаблоны
Многие путают регулярные выражения и glob-шаблоны. Они действительно похожи на вид, но работают на разных уровнях системы.
Glob используется оболочкой Bash для подстановки имён файлов — до запуска команды.
Например:
1ls *.txt
Bash сам подставит все подходящие файлы (notes.txt, todo.txt) и только потом вызовет ls.
Регулярные выражения обрабатываются самой программой — уже после её запуска.
1grep -E ".*\.txt" filelist.txt
Здесь grep сам ищет строки, которые содержат .txt.
Давайте проверим, как вы разобрались с поиском текста в файлах:
Подсчёт строк и слов: команда wc
Мы уже умеем искать файлы (find) и находить нужные строки (grep), но иногда надо просто посчитать: сколько строк в файле, сколько слов или сколько байтов занимает текст.
Для этого в Linux есть команда wc — сокращение от word count (подсчёт слов).
1alice@ubuntu:~$ wc file.txt
2 42 250 1932 file.txt
Вывод для файла file.txt состоит из трёх чисел:
|
Число |
Что означает |
|
42 |
Количество строк |
|
250 |
Количество слов |
|
1932 |
Количество байтов (символов) |
Команда полезна, когда нужно быстро оценить объём текста или количество записей, например строк в логе или строк данных в таблице CSV.
Если нужно вывести только одно из значений, можно добавить опции:
|
Опция |
Что считает |
Пример |
Результат |
|
|
Строки |
|
|
|
|
Слова |
|
|
|
|
Байты (символы) |
|
|
wc работает не только с файлами, но и с потоками данных, полученными из других команд.
Это делает её особенно полезной в сочетании с пайпом:
1alice@ubuntu:~$ grep "ERROR" app.log | wc -l
215
Эта команда считает количество строк, где встречается слово ERROR — удобно, чтобы быстро понять, сколько ошибок в логе.
Аналогично можно посчитать количество файлов в каталоге:
1alice@ubuntu:~$ find . -name "*.py" | wc -l
227
Так мы получаем число файлов с расширением .py в текущем каталоге и во всех подкаталогах.
Аналогичным образом мы можем комбинировать команду wc с cat и less.
Например, мы можем посмотреть, сколько строк в системном файле /etc/passwd (фактически сколько пользователей есть в системе):
1alice@ubuntu:~$ cat /etc/passwd | wc -l
А если указать в аргументах сразу несколько файлов, wc покажет статистику по каждому из них, а также суммарное значение:
1alice@ubuntu:~$ wc report1.txt report2.txt
2 10 56 423 report1.txt
3 14 98 703 report2.txt
4 24 154 1126 total
wc — одна из тех утилит, которые раскрываются именно в сочетании с другими командами.
Она не «ищет» и не «фильтрует», но позволяет превратить любой вывод в конкретное число, что делает её незаменимой при анализе данных и автоматизации.
Сравнение при помощи diff
Иногда нужно понять, чем именно отличаются два файла, например две версии одного документа, два скрипта, две конфигурации.
Для этого в Linux есть команда diff (англ. difference). Она построчно сравнивает два файла и показывает только различия.
Давайте сравним два файла — file1.txt и file2.txt:
1alice@ubuntu:~$ diff file1.txt file2.txt
21c1
3< Hello world
4---
5> Hello Linux
Что мы видим:
|
Символ |
Значение |
|
|
Строка из первого файла ( |
|
|
Строка из второго файла ( |
Строка 1c1 означает, что в первой строке первого файла (1) нужно внести изменение (c — англ. change), чтобы она стала такой же, как первая строка второго файла (1).
Формат, в котором мы получили разницу между файлами, может показаться не очень дружелюбным, но мы можем сделать его более читаемым, добавив опцию -u — для вывода в унифицированном (англ. unified) формате.
Он показывает изменения в контексте — с несколькими строками до и после отличий, как это делают системы контроля версий вроде Git.
1alice@ubuntu:~$ diff -u file1.txt file2.txt
2--- file1.txt
3+++ file2.txt
4@@ -1 +1 @@
5-Hello world
6+Hello Linux
Теперь видно сразу, что именно изменилось: строка с - была удалена, строка с + добавлена.
Такой формат используется в патчах (.patch-файлах) — текстовых файлах с разницей между версиями, которые используются в системах контроля версий кода Git, — поэтому стоит привыкнуть к нему.
Обозначения в diff -u
|
Символ |
Что значит |
|
|
Имя и версия первого файла |
|
|
Имя и версия второго файла |
|
|
Диапазон строк, где найдено отличие |
|
|
Строка, присутствующая только в первом файле |
|
|
Строка, присутствующая только во втором файле |
Давайте сравним другие файлы, с большим количеством строк. У нас есть два файла — old.txt и new.txt:
1alice@ubuntu:~$ cat old.txt
2Apple
3Banana
4Cherry
5Date: 2024
6
7alice@ubuntu:~$ cat new.txt
8Apricot
9Banana
10Cherry
11Date: 2025
Сравним их при помощи команды diff с опцией -u для большей наглядности:
1alice@ubuntu:~$ diff -u old.txt new.txt
2--- old.txt
3+++ new.txt
4@@ -1,4 +1,4 @@
5-Apple
6+Apricot
7 Banana
8 Cherry
9-Date: 2024
10+Date: 2025
Мы сразу видим, какие строки изменились и какие остались прежними. diff показывает минимальный набор изменений, которые нужны для того, чтобы первый файл стал идентичен второму.
Сравнение каталогов
diff умеет сравнивать не только файлы, но и целые каталоги:
1alice@ubuntu:~$ diff -r dir1/ dir2/
Опция -r (англ. recursive) заставляет diff проходить все подкаталоги и файлы внутри них.
В результате вы увидите, какие файлы совпадают, какие отличаются, а какие есть только в одном из каталогов.
1Only in dir1/: config.old
2Only in dir2/: new.txt
3Files dir1/settings.ini and dir2/settings.ini differ
Мы можем быстро сравнить два каталога, найти файлы, которые есть только в одном из них, найти файлы, которые есть в обоих, но различаются по содержанию.
diff — это инструмент для анализа изменений.
Он не вносит изменения сам, а показывает, где и что отличается.
Благодаря ему вы можете точно увидеть, какие строки добавлены, удалены или изменены, будь то текстовый документ, код или конфигурация.
А ещё при помощи diff можно быстро сравнивать каталоги.
Давайте проверим, как вы разобрались с подсчётом и сравнением файлов:
Что дальше
Теперь, когда вы уверенно умеете искать файлы (find), строки в тексте (grep) и быстро получать подсчёты (wc), а ещё сравнивать изменения с помощью diff, самое время разобраться, куда попадает вывод команд и как им управлять. Это фундамент для автоматизации и «склейки» инструментов в конвейеры с использованием пайпов (|).
В следующем параграфе вы узнаете:
- Что такое стандартные потоки
stdin,stdoutиstderr. - Как перенаправлять вывод команды в файл (
>) и дозаписывать в конец (>>). - Как подавать ввод команде из файла (
<). - Как разделять основной вывод и ошибки (
2>) и писать их в разные файлы. - Как объединять перенаправления (например,
./script.sh > out.log 2> err.log). - Что такое код возврата команды и как его проверить (
$?). - Как интерпретировать коды возврата (
0— успех, разные типы ошибок).
После этого вы сможете:
- Собирать «журналы» работы своих команд и скриптов, разносить ошибки по отдельным файлам.
- Строить надёжные проверки в сценариях: «если команда завершилась успешно — делай A, иначе — B».
А пока закрепите материал на практике:
- Отметьте, что урок прочитан, при помощи кнопки ниже.
- Пройдите мини-квиз, чтобы проверить, насколько хорошо вы разобрались с поиском.
- Перейдите к задачам этого параграфа и потренируйтесь.
- Перед этим — загляните в короткий гайд о том, как работает система проверки.
Ключевые выводы по параграфу
findпозволяет искать файлы и каталоги по множеству критериев: по имени (-name), типу (-type), дате изменения (-mtime), размеру (-size) и другим.findможет не только находить, но и выполнять действия над результатами — удалять (-delete), запускать внешние команды (-exec), в том числе с подтверждением (-ok).- Формы
-exec {} \;и-exec {} +различаются: первая запускает команду для каждого файла, вторая — сразу для группы найденных путей и работает быстрее. grepищет строки по шаблону внутри файлов — чувствителен к регистру, но опция-iего игнорирует.grepудобно использовать с пайпами (|) для фильтрации вывода других команд.- Регулярные выражения (regex) — это язык описания шаблонов текста; они позволяют находить сложные совпадения и применяются во множестве утилит.
- Glob-шаблоны (
*.txt,?,[]) подставляются оболочкой до выполнения команды, а регулярные выражения обрабатываются программой во время выполнения. wcподсчитывает строки (-l), слова (-w) и символы (-c) — как в файлах, так и в потоках вывода других команд.diffпострочно сравнивает файлы и каталоги, показывает различия и умеет выводить их в формате патчей (-u), как в системах контроля версий, например Git.
Все эти инструменты прекрасно сочетаются между собой — через конвейеры и перенаправления, с которыми мы подробно познакомимся в следующих параграфах.
