Wildcards, glob-паттерны и архивы
В этой главе соединяются две практические темы: работа с группами файлов и упаковка файлов в архивы. Обе часто встречаются в DevOps: скопировать все конфиги, найти все логи, собрать бэкап директории, посмотреть архив перед распаковкой, сжать большой файл.
Wildcards и glob-экспансия
Shell умеет раскрывать шаблоны имён файлов до запуска команды. Это называется glob-экспансией.
Когда ты пишешь:
ls *.log
команда ls обычно не получает строку *.log. Сначала shell ищет в текущей директории подходящие файлы, например app.log, error.log и access.log.
И уже потом запускает:
ls app.log error.log access.log
Это важная мысль: wildcard раскрывает оболочка, а не сама команда. Поэтому glob работает с ls, cp, mv, rm, cat и другими командами, которые принимают пути к файлам.
Основные символы glob
| Символ | Значение | Пример |
|---|---|---|
* |
Любое количество символов, включая ноль | *.log - все имена, заканчивающиеся на .log |
? |
Ровно один любой символ | data?.txt - data1.txt, но не data10.txt |
[abc] |
Один символ из набора | file[123].txt - file1.txt, file2.txt, file3.txt |
[a-z] |
Один символ из диапазона | [a-z]*.txt - имя начинается со строчной буквы |
[0-9] |
Одна цифра | app[0-9].log - app1.log, но не app12.log |
Примеры:
ls /var/log/*.log
ls data?.txt
ls [aA]pp*.conf
cp *.conf /root/configs/
mv /root/configs/*.conf /root/old_configs/
* шире, чем ?. Паттерн app*.log подходит к app.log, app1.log и app12.log. Паттерн app?.log требует ровно один символ между app и .log, поэтому app12.log не подойдёт.
Скрытые файлы и отсутствие совпадений
Обычный * не подхватывает скрытые файлы, имена которых начинаются с точки.
ls *
не покажет .env. Чтобы явно обратиться к скрытым файлам, нужен шаблон с точкой:
ls .*
или обычный ls -a, если задача именно посмотреть список:
ls -la
Если glob не нашёл совпадений, поведение зависит от настроек shell. В обычном bash шаблон часто остаётся как есть, и команда получает буквальную строку:
ls *.missing
# ls: cannot access '*.missing': No such file or directory
Это не значит, что ls "не умеет wildcard". Это значит, что shell не нашёл файлов, подходящих под шаблон.
Brace expansion: фигурные скобки
Brace expansion похожа на wildcard, но работает иначе: shell не ищет существующие файлы, а просто генерирует строки.
mkdir -p /opt/project/{src,tests,docs}
Shell превратит это в:
mkdir -p /opt/project/src /opt/project/tests /opt/project/docs
Другие примеры:
touch log_{01..10}.txt # создать log_01.txt, log_02.txt ... log_10.txt
cp file.txt{,.bak} # скопировать file.txt в file.txt.bak
mkdir -p app/{config,logs,tmp} # создать app/config, app/logs и app/tmp
Разница:
*.logзависит от реально существующих файлов;{src,tests,docs}не проверяет существование, а просто создаёт варианты текста.
Когда нужны кавычки
Кавычки запрещают shell раскрывать wildcard. Это нужно, когда шаблон должен получить сама команда.
Например, find должен сам искать имена по шаблону:
find /opt/devops/lab7 -name "*.txt"
Если написать без кавычек:
find /opt/devops/lab7 -name *.txt
shell может раскрыть *.txt в текущей директории ещё до запуска find. В результате find получит не шаблон, а список файлов или ошибочную форму аргументов.
Практическое правило:
- для
ls *.log,cp *.conf dest/,mv *.conf dest/кавычки обычно не нужны, потому что раскрытие делает shell; - для
find -name "*.log"кавычки нужны, потому что шаблон должен обрабатыватьfind.
Glob против find
Обычный glob работает в текущей директории или в явно указанном уровне пути:
ls /opt/devops/lab7/*.txt
Это найдёт .txt только прямо внутри /opt/devops/lab7, но не во вложенных директориях.
Для рекурсивного поиска по дереву чаще используют find:
find /opt/devops/lab7 -type f -name "*.txt"
find обойдёт /opt/devops/lab7 и все поддиректории. Поэтому для "все файлы во всех вложенных папках" выбирай find, а для "все файлы рядом" достаточно glob.
Осторожность с wildcard и rm
Wildcard удобно применять с cp и mv, но с rm он требует внимания.
rm *.log
Эта команда удалит все подходящие .log файлы в текущей директории. Перед удалением лучше сначала посмотреть, что именно раскроется:
ls -la *.log
Тот же принцип работает для перемещения:
ls -la /root/configs/*.conf
mv /root/configs/*.conf /root/old_configs/
Сначала проверка списка, потом действие.
Архив и сжатие: разные задачи
Архивирование и сжатие часто путают.
Архивирование объединяет много файлов и директорий в один файл-контейнер.
Сжатие уменьшает размер данных.
tar изначально архивирует: собирает много файлов в один .tar. gzip сжимает один файл. Вместе они дают распространённый формат .tar.gz: сначала собрать файлы через tar, потом сжать gzip.
directory/ -> tar -> backup.tar -> gzip -> backup.tar.gz
Поэтому gzip /etc/nginx/ не подходит для бэкапа директории: gzip работает с одним файлом, а не с деревом файлов. Для директории нужен tar.
tar: создать архив
Базовая команда создания архива:
tar cf backup.tar /opt/project/
Флаги:
c- create, создать архив;f- file, дальше идёт имя файла архива.
Создать сжатый gzip-архив:
tar czf backup.tar.gz /opt/project/
Здесь добавился флаг z: сжать через gzip.
С подробным выводом:
tar czvf backup.tar.gz /opt/project/
v означает verbose: показывать файлы по мере добавления. В скриптах v часто убирают, чтобы вывод был короче.
Практически полезное правило: когда используешь короткие флаги czf, имя архива идёт сразу после группы флагов, потому что f ожидает файл архива:
tar czf /root/backup.tar.gz /opt/devops/lab8/src/
tar: посмотреть содержимое
Перед распаковкой архива полезно посмотреть, что внутри:
tar tf backup.tar
tar tzf backup.tar.gz
Флаги:
t- list, показать содержимое;z- архив с gzip-сжатием;f- имя архива.
Пример:
tar tzf /root/backup.tar.gz > /root/archive_list.txt
Так можно сохранить список файлов архива без распаковки. Это безопасный шаг, особенно если архив получен извне: ты заранее видишь, какие пути будут извлекаться.
tar: извлечь архив
Распаковать .tar.gz в текущую директорию:
tar xzf backup.tar.gz
Флаг x означает extract.
Распаковать в конкретную директорию:
mkdir -p /root/extracted
tar xzf backup.tar.gz -C /root/extracted
-C задаёт целевую директорию для извлечения. Директория должна существовать заранее, поэтому перед этим часто делают mkdir -p.
Извлечь один файл:
tar xzf backup.tar.gz opt/project/config.txt
Путь к файлу должен совпадать с тем, как он записан внутри архива. Поэтому перед точечным извлечением сначала удобно выполнить tar tzf.
gzip и gunzip
gzip сжимает один файл и по умолчанию заменяет его на версию с .gz:
gzip large_file.txt
# large_file.txt исчез, появился large_file.txt.gz
Если нужно сохранить исходник:
gzip -k large_file.txt
Распаковка:
gunzip large_file.txt.gz
gzip -d large_file.txt.gz
Обе команды вернут исходный файл и уберут .gz-версию, если не указаны дополнительные флаги.
Посмотреть сжатый текст без распаковки на диск:
zcat large_file.txt.gz
zless large_file.txt.gz
zless особенно удобен для больших сжатых логов.
zip и unzip
В Linux чаще используют .tar.gz, но .zip встречается при обмене файлами с Windows и macOS.
zip -r archive.zip /opt/project/
unzip archive.zip
unzip -l archive.zip
unzip archive.zip -d /tmp/extract/
zip -rрекурсивно упаковывает директорию;unzip -lпоказывает содержимое без распаковки;unzip -dзадаёт директорию назначения.
Для серверных бэкапов и Linux-пакетов чаще выбирай tar.gz, для передачи пользователям может быть удобнее zip.
Частые сценарии
Сделать бэкап конфигов nginx с датой в имени:
tar czf /root/nginx_backup_$(date +%Y%m%d).tar.gz /etc/nginx/
Посмотреть, что внутри:
tar tzf /root/nginx_backup_20260512.tar.gz
Распаковать в отдельную директорию, не смешивая с текущими файлами:
mkdir -p /tmp/nginx_restore
tar xzf /root/nginx_backup_20260512.tar.gz -C /tmp/nginx_restore
Скопировать проект через tar-поток:
tar czf - /opt/project/ | tar xzf - -C /srv/
Здесь - означает stdout или stdin вместо файла. Первая команда создаёт архив в поток, вторая сразу читает этот поток и распаковывает. Такой приём встречается в администрировании, но на старте важнее уверенно освоить обычные tar czf, tar tzf и tar xzf.
Короткая памятка
| Задача | Команда |
|---|---|
Все .log рядом |
ls *.log |
Все .txt рекурсивно |
find . -type f -name "*.txt" |
Создать .tar.gz |
tar czf backup.tar.gz dir/ |
Посмотреть .tar.gz |
tar tzf backup.tar.gz |
Распаковать .tar.gz |
tar xzf backup.tar.gz |
| Распаковать в директорию | tar xzf backup.tar.gz -C /tmp/out |
| Сжать один файл | gzip file.txt |
Распаковать .gz |
gunzip file.txt.gz |
Смысл всех этих команд один: управлять группами файлов предсказуемо. Сначала проверь список, потом копируй, перемещай, архивируй или удаляй.
