Shell и Bash
| Тип | командная оболочка Unix и язык сценариев |
|---|---|
| Автор Bash | Брайан Фокс (проект GNU) |
| Первый выпуск Bash | 1989 |
| Сопровождающий | Чет Рэми (с 1990-х) |
| Предшественник | Bourne shell (sh, Стивен Борн, 1979) |
| Стандарт | POSIX Shell Command Language |
| Лицензия | GNU GPL v3 (с версии 4.0) |
| Альтернативы | Zsh, fish, dash, ksh |
Командная оболочка (англ. shell, «оболочка», «шелл») — программа, которая читает команды пользователя, запускает соответствующие программы и показывает результат. Это главный текстовый интерфейс Linux и других Unix-подобных систем. Оболочка одновременно служит и интерактивной средой, и языком программирования: последовательность команд можно сохранить в файл-скрипт и запускать как программу.
Bash (Bourne Again Shell — игра слов: «снова Борн» и «рождённый заново») — самая распространённая оболочка Linux, стандартная во многих дистрибутивах и в образах Docker. Под словом «шелл-скрипт» обычно понимают скрипт на Bash или на совместимом с POSIX sh.
История
Первая оболочка Unix (Thompson shell, 1971) умела только запускать команды и перенаправлять ввод-вывод. В 1979 году в Unix Version 7 появилась Bourne shell (sh) Стивена Борна — уже с переменными, условиями и циклами. Затем возникли C shell (csh), KornShell (ksh), а в 1989 году Брайан Фокс написал для проекта GNU свободную замену sh — Bash.[2] Вскоре сопровождение перешло к Чету Рэми, который ведёт проект до сих пор.
Язык оболочки стандартизирован в POSIX: скрипт, использующий только возможности POSIX sh, переносим между Bash, dash, ksh и Zsh.[3] В Debian и Ubuntu /bin/sh — это минималистичная оболочка dash, а Bash используется для интерактивной работы. Apple в macOS Catalina (2019) сменила оболочку по умолчанию на Zsh, оставив в системе старую Bash 3.2 — последнюю версию под GPL v2.[5]
Как оболочка выполняет команду
Прежде чем запустить программу, оболочка разбирает строку в несколько этапов: разбивает её на слова, раскрывает фигурные скобки ({a,b}), тильду (~), переменные ($HOME), подстановку команд ($(date)), арифметику ($((1+2))), затем снова делит результат на слова по пробелам и раскрывает шаблоны имён файлов (*.txt). Только после этого ищется программа в каталогах из переменной PATH и запускается через системные вызовы fork и exec.[1]
Отсюда главное правило: заключайте переменные в двойные кавычки. rm $file при имени файла с пробелом удалит два разных файла, а rm "$file" — ровно один.
Основы синтаксиса
#!/usr/bin/env bash
set -euo pipefail # падать на ошибках и неопределённых переменных
name="мир" # без пробелов вокруг =
echo "Привет, $name"
files=(*.log) # массив (возможность Bash, не POSIX)
echo "логов: ${#files[@]}"
if [[ -d /var/log ]]; then # [[ ]] — расширенная проверка Bash
echo "каталог есть"
fi
for f in "${files[@]}"; do
gzip -- "$f"
done
count=$(grep -c ERROR app.log || true) # подстановка вывода команды
(( count > 0 )) && echo "ошибок: $count"
backup() { # функция
local src=$1
tar czf "/tmp/$(basename "$src").tgz" "$src"
}
backup /etc/nginx
Каждая команда возвращает код выхода: 0 — успех, любое другое число — ошибка. На кодах выхода построены if, операторы && и ||. Строка set -euo pipefail заставляет скрипт останавливаться при первой ошибке, при обращении к неопределённой переменной и при сбое любой команды в конвейере.
Перенаправление и конвейеры
| Запись | Смысл |
|---|---|
cmd > file |
вывод в файл (перезаписать) |
cmd >> file |
дописать в конец файла |
cmd 2> err.log |
поток ошибок в файл |
cmd > out.log 2>&1 |
оба потока в один файл |
cmd < file |
ввод из файла |
a | b |
вывод a на вход b |
Конвейеры — суть философии Unix: маленькие программы, каждая делает одно дело, соединяются в цепочку. Например, десять самых частых IP-адресов в логе: cut -d' ' -f1 access.log | sort | uniq -c | sort -rn | head. Для поиска по тексту используют grep, для преобразования — sed и awk, для обхода файлов — find и xargs.
Интерактивная работа
Bash хранит историю команд (Ctrl+R — поиск по ней), дополняет имена по Tab, поддерживает горячие клавиши в стиле Emacs (Ctrl+A/Ctrl+E — начало и конец строки). Настройки и псевдонимы (alias ll='ls -la') хранятся в ~/.bashrc. Справку по встроенным командам даёт help, по остальным — man-страницы и краткие примеры tldr-pages.
Когда не писать на Bash
Bash хорош для склейки программ, автоматизации развёртывания и коротких сценариев. Когда скрипт перерастает сотню строк, требует сложных структур данных, разбора JSON (хотя есть jq) или обработки ошибок, его лучше переписать на Python. Для проверки скриптов незаменим статический анализатор ShellCheck: он находит пропущенные кавычки, непереносимые конструкции и типичные ловушки.[4]