Глиф Учебники

Урок 8. Скрипты bash: первый скрипт, переменные и аргументы

Курс «Командная строка Linux» · урок 8 из 10 · 4 минуты чтения

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

Первый скрипт

Создайте файл в редакторе nano:

Bash
nano hello.sh

Наберите две строки, сохраните (Ctrl+O, Enter) и выйдите (Ctrl+X):

Bash
#!/bin/bash
echo "Привет из скрипта"

Дайте файлу право на выполнение и запустите:

Терминал
$ chmod +x hello.sh
$ ./hello.sh
Привет из скрипта

./ перед именем значит «файл из текущей папки». Без него оболочка будет искать hello.sh в папках из PATH и не найдёт (урок Переменные окружения, PATH, .bashrc и alias).

Строка #!

Первая строка #!/bin/bash называется shebang («шебанг»). Она говорит системе, какой программой выполнять файл. Пишется в самой первой строке, без пробелов перед #!. Часто встречается и вариант #!/usr/bin/env bash — он находит bash через PATH, это удобно там, где bash лежит не в /bin.

Запустить скрипт можно и без права на выполнение — передав его оболочке: bash hello.sh. А вот sh hello.sh выполнит его другой оболочкой: в Ubuntu и Debian sh — это dash, и всё, что есть только в bash (например, [[ ]] и {1..5}), там не сработает.

hello.sh #!/bin/bash echo "Привет из скрипта" ← shebang: какой программой выполнять файл команда право x кто выполняет ./hello.sh нужно: chmod +x hello.sh bash — по первой строке #!/bin/bash bash hello.sh не нужно bash, строка #! для него — обычный комментарий sh hello.sh не нужно dash в Ubuntu и Debian: нет [[ ]] и {1..5}
Скрипт hello.sh запускается тремя способами: для ./hello.sh нужны chmod +x и строка #!/bin/bash, bash hello.sh права не требует, а sh hello.sh выполнит его оболочкой dash.

Расширение .sh для запуска не нужно, оно только подсказывает человеку, что внутри скрипт. Важны первая строка и право на выполнение.

Комментарии, переменные и кавычки

Всё после # в строке — комментарий, bash его пропускает. Переменные — как в терминале: без пробелов вокруг =.

Bash
#!/bin/bash
# Имя файла с пробелами — обязательно в кавычках
file="отчёт за март.txt"
echo "Файл: $file"
echo 'Файл: $file'
echo "Копия: ${file%.txt}.bak"
Вывод
Файл: отчёт за март.txt
Файл: $file
Копия: отчёт за март.bak

Запись ${file%.txt} — значение переменной без .txt в конце. Таких приёмов в bash много, они описаны в справочнике bash (раздел о раскрытии параметров).

Главное правило скриптов: переменную в команде берите в двойные кавычки — "$file". Без кавычек rm $file получит три аргумента — «отчёт», «за» и «март.txt» — и попробует удалить три других файла.

file="отчёт за март.txt" команда что получает rm rm $file отчёт за март.txt три разных файла rm "$file" отчёт за март.txt один нужный файл
Без кавычек значение file делится по пробелам, и rm получает три аргумента, а с кавычками "$file" — одно имя отчёт за март.txt.

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

$(команда) подставляет вывод команды:

Bash
today=$(date +%F)
count=$(ls | wc -l)
echo "Сегодня $today, файлов в папке: $count"
tar -czf "backup-$(date +%F).tar.gz" ~/projects

date +%F печатает дату в виде 2026-03-12, поэтому у каждого дня будет свой архив. В старых скриптах встречается та же подстановка в обратных кавычках (знак на клавише с буквой Ё) — это устаревшая запись, в новых скриптах пишут $(…).

Целочисленная арифметика — $(( )):

Bash
#!/bin/bash
a=7
b=2
echo "Сумма: $((a + b))"
echo "Частное: $((a / b))"
echo "Остаток: $((a % b))"
echo "Степень: $((a ** b))"
Вывод
Сумма: 9
Частное: 3
Остаток: 1
Степень: 49

Деление целочисленное: дробная часть отбрасывается. Дробные числа bash не считает — для них есть, например, команда bc.

Аргументы

Слова, которые вы пишете после имени скрипта, — его аргументы. Внутри они доступны так:

ЗаписьЧто это
$0имя скрипта, как его запустили
$1, $2 …первый, второй и следующие аргументы
$#сколько аргументов передано
"$@"все аргументы по отдельности, каждый — с сохранением пробелов

Скрипт args.sh:

Bash
#!/bin/bash
echo "Скрипт: $0"
echo "Аргументов: $#"
echo "Первый: $1"
echo "Второй: $2"
Терминал
$ ./args.sh отчёт.txt "фото с моря.jpg"
Скрипт: ./args.sh
Аргументов: 2
Первый: отчёт.txt
Второй: фото с моря.jpg

Кавычки при запуске сделали «фото с моря.jpg» одним аргументом. Если аргумент не передан, $2 просто пустой — ошибки не будет, поэтому важные аргументы проверяют (об условиях — в следующем уроке).

кавычки — один аргумент с пробелами ./args.sh отчёт.txt "фото с моря.jpg" $0 ./args.sh $1 отчёт.txt $2 фото с моря.jpg $# 2 имя скрипта первый аргумент второй аргумент сколько их "$@" — все аргументы, каждый отдельно
При запуске ./args.sh отчёт.txt "фото с моря.jpg" имя скрипта попадает в $0, аргументы — в $1 и $2, их число 2 — в $#, а "$@" собирает все аргументы.

Ввод с клавиатуры: read

Bash
#!/bin/bash
read -r -p "Как вас зовут? " name
echo "Привет, $name"
Терминал
$ ./ask.sh
Как вас зовут? Анна
Привет, Анна

read ждёт строку и кладёт её в переменную; -p — текст приглашения, -r — не трогать обратную косую черту во вводе. Пароль читают с ключом -s — набранное не показывается.

Код возврата

Каждая команда, заканчиваясь, сообщает код возврата (exit code): 0 — успех, любое другое число — ошибка. Код последней команды хранится в $?:

Терминал
$ grep -q root /etc/passwd
$ echo $?
0
$ grep -q nosuchuser /etc/passwd
$ echo $?
1

grep -q ничего не печатает, а только сообщает кодом, нашлось ли. Частые коды:

КодЗначение
0успех
1общая ошибка; у grep — «не найдено»
2неверное использование команды, серьёзная ошибка
126файл найден, но не запускается (нет права на выполнение)
127команда не найдена
130команда прервана Ctrl+C

Скрипт задаёт свой код командой exit: exit 0 — всё хорошо, exit 1 — ошибка. Без exit код скрипта — это код последней выполненной в нём команды. Коды нужны, чтобы другие программы (cron, systemd, другие скрипты) понимали, удалась ли работа.

Как искать ошибки

Коротко

Проверьте себя

1. Зачем в первой строке скрипта пишут #!/bin/bash?
2. Что выведет echo "$((10 / 4))" в bash?
3. Скрипт запущен командой ./copy.sh a.txt b.txt c.txt. Чему равно $#?
4. Какой код возврата означает, что команда выполнилась успешно?