Урок 8 из 8 · 25 мин · обновлено

Первый скрипт на bash

Как записать команды в файл и запускать их одной командой: строка #!/bin/bash, переменные, подстановка команд, аргументы, условия и циклы. Пишем скрипты для резервной копии и отчёта по логу.

Скрипт — команды в файле

Если одни и те же команды приходится набирать снова и снова, их записывают в файл — скрипт — и запускают одной командой. Сделаем резервную копию учебной папки:

Терминал
#!/bin/bash
# Резервная копия папки practice с датой в имени архива
today=$(date +%Y-%m-%d)
mkdir -p ~/backups
tar -czf ~/backups/practice-$today.tar.gz -C ~ practice && echo "Готово: practice-$today.tar.gz"

Сохраните это в файл ~/backup.sh любым редактором. В терминале проще всего nano backup.sh: вставьте текст, сохраните Ctrl+O и Enter, выйдите Ctrl+X. Затем:

Терминал
chmod +x backup.sh
./backup.sh
Результат
Готово: practice-2026-10-21.tar.gz
  • #!/bin/bash — первая строка: каким интерпретатором выполнять файл;
  • строки с # дальше — комментарии;
  • tar -czf архив -C ~ practice — упаковать папку practice из домашней папки в сжатый архив;
  • chmod +x — разрешить запуск, как в уроке 6.

Переменные и подстановка

Терминал
name="Анна"
echo "Привет, $name"
echo 'Привет, $name'
Результат
Привет, Анна
Привет, $name
  • переменную создают как имя=значение, без пробелов вокруг =. С пробелами bash решит, что name — это команда;
  • значение берут через $имя;
  • в двойных кавычках переменные подставляются, в одинарных — нет, текст выводится как есть.

$(команда) подставляет результат команды. В скрипте выше today=$(date +%Y-%m-%d) сохраняет сегодняшнюю дату, и она попадает в имя архива.

&& между командами значит: выполни вторую, только если первая прошла успешно. Без него скрипт написал бы «Готово», даже если tar не смог создать архив.

Аргументы и условия

Скрипту можно передавать аргументы, как обычной команде. Внутри первый аргумент — $1, второй — $2. Напишем errors.sh, который считает ошибки в любом логе:

Терминал
#!/bin/bash
# Считает ошибки в логе, имя файла — первый аргумент
file=$1

if [ ! -f "$file" ]; then
  echo "Нет такого файла: $file"
  exit 1
fi

echo "Ошибок в $file: $(grep -c ERROR "$file")"
Терминал
./errors.sh app.log
./errors.sh nope.log
Результат
Ошибок в app.log: 3
Нет такого файла: nope.log
  • if [ условие ]; then … fi — условие. Пробелы внутри квадратных скобок обязательны;
  • -f "$file" — файл существует, ! — отрицание: «если файла нет»;
  • exit 1 — завершить скрипт с ошибкой. Код 0 значит «успех», любой другой — «что-то пошло не так»;
  • переменные с именами файлов берут в кавычки "$file", чтобы не сломаться на именах с пробелами.

Циклы

for повторяет команды для каждого элемента:

Терминал
for f in photos/jpg/*.jpg; do
  echo "Файл: $f"
done
Результат
Файл: photos/jpg/cat.jpg
Файл: photos/jpg/dog.jpg

Так переименовывают сотни файлов, обрабатывают каждую строку списка или проверяют несколько серверов подряд. Хороший следующий шаг — запускать скрипты по расписанию: в Linux для этого есть cron.

Попробуйте сами. Напишите скрипт add-date.sh, который добавляет к имени каждого файла .jpg в указанной папке сегодняшнюю дату: cat.jpg → 2026-10-21-cat.jpg. Папку передайте аргументом. Если папки нет, скрипт сообщает об этом и завершается.

Решение
Терминал
#!/bin/bash
# Добавляет дату в начало имени каждого .jpg в папке
dir=$1
today=$(date +%Y-%m-%d)

if [ ! -d "$dir" ]; then
  echo "Нет такой папки: $dir"
  exit 1
fi

for f in "$dir"/*.jpg; do
  name=$(basename "$f")
  mv "$f" "$dir/$today-$name"
  echo "$name → $today-$name"
done
Терминал
chmod +x add-date.sh
./add-date.sh photos/jpg
Результат
cat.jpg → 2026-10-21-cat.jpg
dog.jpg → 2026-10-21-dog.jpg

-d проверяет, что это папка. basename отрезает путь и оставляет только имя файла. Переименовываем через mv, как в уроке 3.

Перед запуском таких скриптов на важных файлах сначала замените mv на echo mv — скрипт покажет, что сделает, ничего не трогая.

Мини-тест: проверьте себя

Закрепите урок: несколько вопросов, разбор ответов — в конце.

  1. Зачем в первой строке скрипта пишут #!/bin/bash?

  2. Почему запись name = "Анна" не создаёт переменную?

  3. Что выведет echo "Ошибок: $(grep -c ERROR app.log)", если в логе 3 ошибки?

  4. Что делает запись tar … && echo "Готово"?