Bash-скрипты: аргументы, условия и циклы
40 мин
В прошлом уроке вы написали первый скрипт — одну команду в файле. Настоящие скрипты принимают аргументы, проверяют условия и обрабатывают много файлов в цикле. Это главный инструмент автоматизации: резервные копии, разбор журналов, массовые проверки, сканеры.
Каркас скрипта
#!/bin/bash
set -euo pipefail # падать на ошибках, а не продолжать молча
LOG_DIR="$HOME/logs" # переменная: без пробелов вокруг =
echo "Разбираю $LOG_DIR"
set -euo pipefail — хорошая привычка:
-e— остановиться, если команда завершилась с ошибкой;-u— ошибка при обращении к несуществующей переменной (спасает отrm -rf "$DIR/"*с пустымDIR);-o pipefail— конвейер считается неуспешным, если упала любая его часть.
Аргументы
| Переменная | Значение |
|---|---|
$0 | имя скрипта |
$1, $2 … | первый, второй … аргумент |
$# | количество аргументов |
"$@" | все аргументы, каждый отдельно |
$? | код возврата последней команды |
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Использование: $0 ФАЙЛ" >&2 # >&2 — в поток ошибок
exit 1
fi
wc -l < "$1"
Коды возврата и условия
Каждая команда возвращает число: 0 — успех, всё остальное — ошибка. На этом построены условия:
if grep -q 'root' /etc/passwd; then
echo "нашёл"
fi
[ -f "$file" ] # существует и это обычный файл
[ -d "$dir" ] # каталог
[ -r "$file" ] # можно прочитать
[ -z "$var" ] # строка пустая
[ "$a" = "$b" ] # строки равны
[ "$n" -gt 10 ] # число больше 10 (-lt, -ge, -le, -eq, -ne)
Короткая запись: команда1 && команда2 выполнит вторую только при успехе первой, || — только при
ошибке: mkdir -p "$out" || exit 1.
Циклы
for f in "$HOME"/logs/*.log; do # по файлам
echo "$(basename "$f") $(grep -c ERROR "$f")"
done
for i in 1 2 3; do echo "$i"; done # по списку
while read -r ip; do # по строкам файла
echo "проверяю $ip"
done < targets.txt
basename отрезает путь и оставляет имя файла: /home/student/logs/app.log → app.log.
Кавычки: главный источник ошибок
| Запись | Что происходит |
|---|---|
"$var" | значение подставляется целиком, пробелы сохраняются — используйте так |
$var | значение разбивается по пробелам и раскрываются шаблоны: файл my notes.txt станет двумя |
'$var' | никакой подстановки: буквально $var |
$(команда) | подставить вывод команды |
Правило: всегда берите переменные в двойные кавычки, если не уверены в обратном.
С точки зрения безопасности
Скрипт, который подставляет недоверенные данные (имена файлов, ввод пользователя) без кавычек или
передаёт их в eval, уязвим для внедрения команд. Имя файла ; rm -rf ~ — вполне допустимое имя
в Linux. Кавычки, -- перед аргументами (rm -- "$f") и отказ от eval закрывают большинство таких
проблем.
🧪 Практика
Напишите скрипт, который проверяет аргументы и считает строки в файле, и скрипт с циклом, который подсчитывает ошибки в каждом журнале.