linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • Симулятор
  • База знаний
  • Собеседование
Index
Categories
All entries
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
home/linux/kb/Команды/bash-scripting

kb/commands ── Команды ── beginner

bash-скрипты - основы и идиомы

Bash-скрипт - текстовый файл с shebang `#!/usr/bin/env bash` и `chmod +x`. Обязательный starting point - `set -euo pipefail` и `shellcheck` для проверки.

view as markdownaka: bash-script, shell-script, bash-strict-mode, shellcheck

Когда писать bash, а когда нет

Bash хорош для:

  • Связки CLI-утилит: pipe, фильтрация, redirect, exit-code-проверки.
  • Скриптов установки/деплоя/CI: запустить серию команд, остановиться при ошибке.
  • Автоматизации задач системного администрирования.

Перепиши на Python/Go когда:

  • Нужны массивы объектов / map'ы / JSON-парсинг.
  • Скрипт > ~150 строк или есть функции с параметрами.
  • Нужны concurrency, тесты, типы.

Когда дочитал до момента «нужен bash-array со словарём внутри» - писать не на bash.

Минимальный безопасный скелет

bash
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# код тут

Что это:

  • #!/usr/bin/env bash - портативный shebang. /bin/bash может отсутствовать на macOS/BSD/в контейнерах с busybox.
  • set -e - упасть на первой ошибке (любая команда с non-zero exit).
  • set -u - упасть на использовании необъявленной переменной.
  • set -o pipefail - exit-code пайпа = exit-code последней упавшей команды, а не последней. Без этого false | true = success.
  • IFS=$'\n\t' - split только по newline и tab, не по пробелам. Защита от файлов с пробелами в именах в for f in $(ls)-стиле.

Без set -euo pipefail ошибки молча игнорируются и скрипт продолжает делать неправильное.

Переменные

bash
name="serge"             # без пробелов вокруг =
echo "$name"             # ВСЕГДА в кавычках, иначе ломается на пробелах
echo "${name}_user"      # ${} когда нужно ограничить имя
port=8080
echo "URL: http://localhost:${port}/api"

Кавычки:

  • "..." - interpolate $var, $(...), escape'ы. Default, всегда используй.
  • '...' - буквально, никаких подстановок.
  • Без кавычек - word splitting + glob expansion. Опасно с пробелами и *.

Правило: всегда оборачивай переменные в "$var". Даже когда «не нужно».

Command substitution - $(cmd)

bash
today=$(date +%F)
files=$(find /var/log -name '*.log' | wc -l)
echo "Today: ${today}, log files: ${files}"

Старая школа `cmd` тоже работает, но $() лучше:

  • Можно вкладывать: $(echo $(date)).
  • Меньше escape-головной боли.

Условия - [[ ]] и (( ))

В bash есть три синтаксиса проверок. Используй современные.

Строки/файлы - [[ ]]

bash
if [[ -f /etc/passwd ]]; then echo "exists"; fi
if [[ -z "$var" ]]; then echo "empty"; fi
if [[ "$user" == "root" ]]; then echo "root"; fi
if [[ "$msg" =~ ^ERROR ]]; then echo "regex match"; fi
ТестЧто проверяет
-f pathregular file существует
-d pathкаталог
-e pathсуществует (любого типа)
-r pathчитаемо
-w pathзаписываемо
-x pathисполняемо
-z "$s"строка пуста
-n "$s"строка не пуста
"$a" == "$b"равенство строк
"$a" != "$b"не равно
"$s" =~ regexregex-match

Старый [ ... ] (POSIX) тоже работает, но [[ ]] богаче и не требует кавычек вокруг переменных. Используй [[ ]] всегда - кроме случаев когда пишешь под /bin/sh.

Числа - (( ))

bash
if (( count > 100 )); then echo "many"; fi
if (( $# < 2 )); then echo "need 2+ args"; exit 1; fi
total=$(( a + b ))            # арифметика

Внутри (( )) $ для переменных не обязателен и нет кавычек - это арифметический контекст.

Циклы

bash
# for-in по списку
for host in web1 web2 web3; do
    ssh "$host" "uptime"
done
# for по файлам - НЕ через $(ls), а через glob
for f in /var/log/*.log; do
    echo "Processing $f"
done
# while-read построчно (стандарт для обработки файлов)
while IFS= read -r line; do
    echo "Got: $line"
done < input.txt
# C-style
for ((i=0; i<10; i++)); do
    echo "$i"
done

while IFS= read -r - единственный правильный способ читать файл построчно. IFS= запрещает обрезку whitespace, -r - не обрабатывать backslash-escapes. Иначе строки с табами или \n ломаются.

Никогда: for f in $(ls *.txt) - ломается на пробелах в именах, glob-expansion двойная. Используй for f in *.txt напрямую.

Функции

bash
greet() {
    local name="${1:-world}"     # дефолт если $1 не передан
    echo "Hello, $name!"
}
greet             

▸Hello, world!

greet "serge"     

▸Hello, serge!

Аргументы - $1, $2, ..., $@ (все), $# (количество), $0 (имя скрипта).

local обязательно для всех переменных в функциях. Без local они глобальные и портят состояние снаружи. Это самая частая bash-ошибка.

Redirect и pipe

bash
cmd > file              # stdout → file (перезапись)
cmd >> file             # stdout → file (append)
cmd 2> file             # stderr → file
cmd > file 2>&1         # stdout И stderr → file (порядок важен!)
cmd &> file             # bash-shortcut для того же
cmd < file              # stdin из файла
cmd1 | cmd2             # stdout cmd1 → stdin cmd2
cmd1 |& cmd2            # stdout И stderr → stdin cmd2
cmd > /dev/null 2>&1    # тихо, всё в /dev/null

Heredoc для multi-line input:

bash
cat <<EOF > /etc/myapp.conf
port=8080
user=$USER       # подставится - без кавычек у EOF
EOF
cat <<'EOF' > /etc/myapp.conf
port=$PORT       # НЕ подставится - кавычки вокруг EOF
EOF

Exit codes - главный механизм ошибок

Каждая команда возвращает int 0-255. 0 = success, всё остальное - ошибка.

bash
cmd && echo "ok"            # выполнится только если cmd succeeded
cmd || echo "failed"        # выполнится только если cmd failed
cmd || exit 1               # упасть если cmd failed
cmd1; cmd2                  # cmd2 запустится независимо
echo $?                     # exit code последней команды

Проверка нескольких:

bash
if cmd1 && cmd2; then echo "both ok"; fi

С set -e отдельные cmd || true = «знаю что может упасть, продолжай».

Argv-парсинг - getopts

bash
while getopts ":vh:f:" opt; do
    case $opt in
        v) verbose=1 ;;
        h) host="$OPTARG" ;;
        f) file="$OPTARG" ;;
        \?) echo "Unknown: -$OPTARG"; exit 1 ;;
        :) echo "-$OPTARG needs argument"; exit 1 ;;
    esac
done
shift $((OPTIND-1))         # сдвинуть позиционные за флагами

Для long-options (--verbose) bash напрямую не умеет - используй getopt (внешняя утилита) или Python/Go.

Дебаг

bash
bash -n script.sh           # только синтаксис, не запускать
bash -x script.sh           # трейс выполнения каждой команды
set -x                      # включить трейс посередине скрипта
set +x                      # выключить

В трейс-режиме каждая команда печатается в stderr с префиксом +. Самый быстрый способ понять «где падает».

shellcheck - обязательный линтер

Любой нетривиальный скрипт прогонять через shellcheck. Он ловит:

  • Забытые кавычки $var без ".
  • Использование $(ls) в for.
  • [ ... -a ... ] вместо [[ ... && ... ]].
  • Несовпадающие кавычки.
  • Глобальные переменные в функциях.
bash
sudo apt install shellcheck         # Debian/Ubuntu
sudo dnf install ShellCheck         # Fedora
shellcheck script.sh

Интегрировать в CI и pre-commit. Без shellcheck любой bash-проект накапливает скрытые баги.

Типичные ловушки

  • Не квотированные $var: rm $file для file="my doc.txt" сделает rm my doc.txt (две жертвы). Всегда rm "$file".
  • set -e не ловит всё: внутри if, после ||, в pipe (без pipefail), в подоболочке. Проверять явно || после критичных команд.
  • cd без проверки: cd /opt/app && do_stuff, не cd /opt/app; do_stuff. Если cd упадёт - do_stuff запустится в текущем каталоге.
  • Trap для cleanup: trap 'rm -f "$tmp"' EXIT чтобы временные файлы удалились даже при kill -2.
  • bash -c vs sh -c: на системах где sh = dash (Debian/Ubuntu) bash-syntax не работает в sh -c.

§ команды

bash
shellcheck script.sh

Линтер для bash - ловит 90% типичных ошибок. Запускать перед каждым коммитом

bash
bash -x script.sh

Запуск с трейсом - каждая команда печатается в stderr перед выполнением

bash
bash -n script.sh

Только синтаксис-чек, не запускает - для CI или быстрой проверки

bash
set -euo pipefail

Безопасный strict-mode. Первая строка любого нового скрипта

bash
trap 'rm -f "$tmpfile"' EXIT

Cleanup при выходе по любой причине - даже kill -TERM или Ctrl+C

§ см. также

  • cmd-sedsed - потоковый редактор текстаsed - потоковый редактор: каждой строке применяет команды (`s/a/b/`, `d`, `p`, ...). `-i` правит файл на месте; `-E` включает ERE; адресный диапазон `/start/,/end/` фильтрует блок. Hold space - вторая память.
  • cmd-awkawk - обработка структурированного текста по полямawk бьёт строку на поля по FS (default - whitespace) и применяет pattern { action }. `$1..$NF`, `NR` (счётчик), BEGIN/END для пролога и итогов. Покрывает 80% задач "обработать колонки" без Python.
  • cmd-jqjq - запросы и трансформация JSONjq - запросный язык для JSON в shell. `.field`, `.array[]`, `select(...)`, `map(...)`, пайпы внутри выражения через `|`. `-r` снимает кавычки, `-c` пакует в строку. Идеально для curl + jq + grep.
  • cmd-cron-crontabcron и crontab - расписание задачcron - демон, который читает crontab-файлы и запускает задачи по расписанию. Формат: `min hour day month weekday command`. Anacron для выключаемых машин. На systemd-системах часто заменяется timers.
  • cmd-rsyncrsync - инкрементальная синхронизация файловrsync копирует только изменённые блоки файлов локально или по SSH. `-avz` базовая комбинация (archive + verbose + compress). `--delete` зеркалирует. `--dry-run` обязателен перед первым запуском.
  • shebangShebang: первая строка скриптаПервая строка скрипта вида `#!/usr/bin/env bash` говорит ядру какой интерпретатор поднимать. Без shebang скрипт запускается через текущий shell - и в bash-режиме на проде ломается на /bin/sh.
  • process-substitutionProcess substitution: <(cmd) и >(cmd)Bash-синтаксис `<(cmd)` подставляет команду как «псевдо-файл» на чтение. `>(cmd)` - на запись. Получаешь временный файл которого не нужно убирать.
  • xargs-and-find-execxargs и find -exec - массовые операцииДва способа применить команду к набору файлов: `find ... -exec cmd {} +` (внутри find) и `... | xargs cmd` (через pipe). Для безопасности с пробелами/спецсимволами - связка `find -print0 | xargs -0`.
  • helm-chartsHelm charts - пакетный менеджер для KubernetesHelm - пакетный менеджер k8s. Chart - папка с Chart.yaml, values.yaml и templates/ (Go-templates над YAML). Releases хранятся в Secret namespace'а; upgrade/rollback атомарны. Альтернатива - kustomize (без templating, патчи).

§ упоминается в уроках

  • ›beginner-12-shell-scripting
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки