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

← все кластеры

Bash и shell-скриптинг

Базовый кластер для всех, кто пишет глейн-код в Linux. Вопросы про strict mode, обработку аргументов, сигналы в bash, разницу между pipe и process substitution. Кажется поверхностным, но именно здесь чаще всего ловят неаккуратность - один пропущенный `IFS=` ломает скрипт на файле с пробелом в имени.

6 вопросов · ~18 мин чтения

Questions

На этой странице

  1. 01Что делает `set -euo pipefail` и зачем его ставить первой строкой?
  2. 02Что такое IFS и почему `for f in $(ls)` это плохо?
  3. 03В чём разница между `cmd1 | cmd2` и `cmd1 <(cmd2)`?
  4. 04Как поймать SIGTERM в bash-скрипте и сделать cleanup?
  5. 05В чём разница между heredoc (`<<EOF`) и here-string (`<<<`)?
  6. 06Чем `find ... -exec` отличается от `find ... | xargs`?

#set-euo-pipefail

intermediateчасто

Что делает `set -euo pipefail` и зачем его ставить первой строкой?

Что отвечать

`-e` - exit при любой ошибке (non-zero exit code). `-u` - exit при использовании unset переменной. `-o pipefail` - exit-code пайплайна равен последнему НЕнулевому, а не последней команды (без него `false | true` это успех). Эти три флага превращают bash из forgiving shell в strict mode, который ловит большинство тихих багов сразу.

Что хотят услышать

Senior должен: - назвать каждый флаг по отдельности и привести пример где он ловит баг (особенно `-u`: typo в имени переменной не вызовет ошибку без него) - сказать что `-e` имеет коварство: `cmd && other` или внутри `if` не вызовут exit при ошибке cmd - это by design - упомянуть `set -x` для трейсинга и `set -E` (errtrace) для наследования trap'ов в функциях - назвать `IFS=$'\n\t'` как четвёртый компонент strict mode (защита от word-splitting на пробелах)

Подводные камни

  • ✗ Думать что `set -e` ловит ВСЕ ошибки - нет, в условиях и pipe без pipefail он молчит
  • ✗ Использовать unset-переменные через `${VAR:-default}` без знания что это обходит `-u`
  • ✗ Не ставить strict mode в production-скриптах - тихий баг ждёт своего часа

Follow-up

  • ? Что делает `${VAR:-default}` и почему это работает с `set -u`?
  • ? Чем `set -E` отличается от `set -e` для trap-наследования?
  • ? Как `pipefail` влияет на exit-code многоступенчатого пайплайна?

Глубина в базе знаний

  • Bash strict mode: set -euo pipefail
  • bash-скрипты - основы и идиомы
tags: bash, strict-mode, error-handling

#ifs-and-word-splitting

juniorчасто

Что такое IFS и почему `for f in $(ls)` это плохо?

Что отвечать

IFS (Internal Field Separator) - переменная, по которой bash режет результат подстановки на слова. По умолчанию это пробел, таб, перевод строки. Поэтому `for f in $(ls)` ломается на файлах с пробелом в имени: `my file.txt` становится двумя «словами». Правильно: `for f in *.txt` (glob) или `find ... -print0 | xargs -0` для произвольных имён.

Что хотят услышать

Кандидат должен: - объяснить word-splitting: bash берёт результат `$(...)`, режет по IFS, потом каждый кусок ещё раз раскрывает (glob) - назвать кавычки `"$var"` как защиту от word-splitting в большинстве случаев (но не в for-цикле, там кавычки не помогут) - привести правильные паттерны: - glob (`for f in *.txt`) - если все файлы в одном каталоге - `find -print0 | xargs -0` - если рекурсивно - `while IFS= read -r line; do ...; done < file` - для построчного чтения - упомянуть «ParsingLs» как канонический BashFAQ-вопрос

Подводные камни

  • ✗ Использовать `for f in $(ls)` - ломается на пробелах, табах, newline'ах в именах
  • ✗ Забыть `IFS=` перед `read -r` - leading/trailing spaces съедятся
  • ✗ Думать что `"$var"` решает word-splitting в for-цикле

Follow-up

  • ? Почему `while read line` без `-r` это плохо?
  • ? Что выведет `IFS=: read a b c <<< "x:y:z"`?
  • ? Чем `find -print0` отличается от `find -print` для xargs?

Глубина в базе знаний

  • Bash strict mode: set -euo pipefail
  • xargs и find -exec - массовые операции
tags: bash, ifs, gotchas

#pipe-vs-process-substitution

intermediateиногда

В чём разница между `cmd1 | cmd2` и `cmd1 <(cmd2)`?

Что отвечать

Pipe (`|`) - cmd1 пишет в stdout, cmd2 читает из stdin, обе бегут параллельно. Process substitution (`<(...)`) - bash запускает команду и подставляет вместо `<(...)` путь к именованному pipe (`/dev/fd/N`), который cmd1 читает как обычный файл. Pipe для линейных потоков; process substitution когда команда ждёт файл, а не stdin (типа `diff <(cmd1) <(cmd2)`).

Что хотят услышать

Senior должен: - объяснить что process substitution создаёт fd через `pipe()` + передаёт путь типа `/dev/fd/63` команде - назвать классический use case: `diff <(sort a.txt) <(sort b.txt)` - diff требует два файла, а не два stdin - упомянуть что process substitution не работает в pure POSIX shell (только bash, ksh, zsh) - в `/bin/sh` (dash на Debian) сломается - привести разницу с named pipe (`mkfifo`): process substitution автоматически чистит за собой, а mkfifo нужно явно `rm`

Подводные камни

  • ✗ Использовать process substitution в `/bin/sh` скрипте - синтаксис сломается
  • ✗ Думать что `<(...)` возвращает содержимое - нет, путь к fd
  • ✗ Забыть что внутри `<(...)` это subshell - переменные не экспортируются наружу

Follow-up

  • ? Что покажет `ls -la <(echo hello)`?
  • ? Почему `cmd1 | while read; do COUNT=$((COUNT+1)); done; echo $COUNT` не работает как ожидаешь?
  • ? Чем `>(...)` отличается от `<(...)`?

Глубина в базе знаний

  • Process substitution: <(cmd) и >(cmd)
  • Here-doc и here-string: данные внутри скрипта
tags: bash, pipes, advanced

#trap-signals-bash

intermediateиногда

Как поймать SIGTERM в bash-скрипте и сделать cleanup?

Что отвечать

`trap 'cleanup_function' SIGTERM SIGINT EXIT`. Когда скрипт получит указанный сигнал, выполнится `cleanup_function` перед exit. `EXIT` - специальный псевдо-сигнал, срабатывает при любом завершении (включая ошибку из `set -e`). Типичный паттерн: trap на EXIT для удаления temp-файлов, trap на SIGTERM для graceful shutdown демона.

Что хотят услышать

Senior должен: - назвать что bash блокирует обработку сигнала пока syscall не вернётся (т.е. `sleep 100` в скрипте отреагирует на SIGTERM только после завершения) - сказать что `trap '' SIGTERM` - игнорировать сигнал (пустой обработчик) - привести идиому temp-cleanup: ``` TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' EXIT ``` - упомянуть что в скрипте под `set -e` ошибка может затриггерить EXIT trap раньше ожидаемого - cleanup должен быть idempotent - назвать `trap -p` для просмотра текущих trap'ов

Подводные камни

  • ✗ Думать что trap отрабатывает мгновенно - bash ждёт окончания текущего syscall
  • ✗ Не использовать EXIT trap для temp-файлов - оставляешь мусор
  • ✗ Использовать `trap 'rm -rf $TMPDIR' EXIT` без кавычек - если TMPDIR пустой, это `rm -rf` в корне

Follow-up

  • ? Что произойдёт если родительский bash-скрипт убит, а дочерние процессы ещё работают?
  • ? Как сделать чтобы child-процессы тоже получили SIGTERM при завершении скрипта?
  • ? Зачем нужен `trap '' SIGINT` в некоторых production-скриптах?

Глубина в базе знаний

  • bash-скрипты - основы и идиомы
  • Сигналы (SIGTERM, SIGKILL, SIGHUP)
tags: bash, signals, cleanup

#heredoc-vs-herestring

juniorиногда

В чём разница между heredoc (`<<EOF`) и here-string (`<<<`)?

Что отвечать

Heredoc - многострочный stdin до маркера-разделителя. `<<EOF` раскрывает переменные, `<<'EOF'` (с кавычками) - не раскрывает. Here-string `<<<` - одна строка как stdin: `grep pattern <<< "$var"`. Heredoc для длинных текстов и SQL-запросов; here-string для подачи одной переменной в команду, ожидающую stdin.

Что хотят услышать

Кандидат должен: - различить `<<EOF` (раскрывает `$var`, `$(cmd)`, бэктики) и `<<'EOF'` (literal, ничего не раскрывает) - типичный gotcha - сказать что `<<-EOF` (с минусом) игнорирует leading табы - для красивой индентации внутри функций - привести пример here-string как замены echo+pipe: `bc <<< "1+1"` vs `echo "1+1" | bc` - короче и без extra-процесса - назвать что heredoc - bash-feature, но `<<EOF` есть и в POSIX sh

Подводные камни

  • ✗ Использовать `<<EOF` для secret'а, не зная что внутри `$var` раскрывается
  • ✗ Забыть `-` в `<<-EOF` и получить EOF в неожиданном столбце
  • ✗ Использовать `<<<` в POSIX sh - не поддерживается, нужен bash

Follow-up

  • ? Что выведет `cat <<EOF\n\$HOME\nEOF`?
  • ? Чем `<<` отличается от `<<-` в практическом use case?
  • ? Как через heredoc передать SQL-запрос с одинарными кавычками?

Глубина в базе знаний

  • Here-doc и here-string: данные внутри скрипта
  • bash-скрипты - основы и идиомы
tags: bash, heredoc, gotchas

#xargs-vs-find-exec

intermediateиногда

Чем `find ... -exec` отличается от `find ... | xargs`?

Что отвечать

`find -exec cmd {} \;` - запускает cmd ОТДЕЛЬНО на каждый файл. `find -exec cmd {} +` - пакетный режим, как xargs, складывает в одну командную строку. `find | xargs` - другой процесс, работает аналогично `+`, но опасен на пробелах в именах. Безопасная форма: `find -print0 | xargs -0 cmd` (NUL-разделитель). На современных find `-exec ... +` обычно достаточно, xargs нужен когда хочется параллелизм через `-P`.

Что хотят услышать

Senior должен: - различить `\;` (one-by-one, медленно) и `+` (batched, быстро) - назвать `-print0 | xargs -0` как защиту от пробелов - сказать что `xargs -P $(nproc)` даёт параллельную обработку без GNU parallel - это часто достаточно - упомянуть `xargs -n 1` для one-arg-at-a-time когда команда не принимает несколько - назвать ARG_MAX (`getconf ARG_MAX` обычно 2M) как лимит длины командной строки - на больших списках xargs автоматически бьёт на батчи

Подводные камни

  • ✗ Использовать `find | xargs cmd` без `-print0/-0` - ломается на файлах с пробелом, табом, newline
  • ✗ Использовать `-exec ... \;` на тысячах файлов - тысячи fork-exec, медленно
  • ✗ Не знать про `xargs -P` и тянуться за GNU parallel

Follow-up

  • ? Чем `-exec ... \;` отличается от `-exec ... +`?
  • ? Что делает `xargs -I {}` и зачем оно нужно?
  • ? Как `xargs -P 8 -n 1` работает с порядком вывода?

Глубина в базе знаний

  • find - поиск файлов по предикатам
  • xargs и find -exec - массовые операции
tags: bash, find, xargs
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки