Читаем файл построчно в Bash

Опубликовано 22 сент. 2025 г.

Довольно часто нужно быстро загрузить файл построчно в массив.

Как делает мальчик:

lines=()
while IFS= read -r line; do
  lines+=("$line")
done < file.txt

echo "Первая строка: ${lines[0]}"
echo "Всего строк: ${#lines[@]}"
ЧИТАТЬ ПЕРВЫМ В ТЕЛЕГРАМ

Как делает мужчина:

mapfile -t lines < file.txt

echo "Первая строка: ${lines[0]}"
echo "Всего строк: ${#lines[@]}"

В первом варианте много кода, НО, работает везде. Во втором варианте, работает только в bash ≥4.0, но кода в разы меньше и не жрет CPU.

Совет: если пишешь скрипт под bash — всегда используй mapfile. Если нужен кросс-шелл (sh,dash,ash) — оставайся на цикле.

Либо расширь второй вариант и укажи:

#!/usr/bin/env bash

Это гарантирует, что твой скрипт выполнится именно через bash, а не через системный sh (который может быть dash, ash, ksh и т.п.).

env ищет bash в $PATH, так что это более переносимо, чем жёстко указывать #!/bin/bash

Ну и прицепом можешь добавить: set -euo pipefail

Это включение «строгого режима» в баше:

-e — выход из скрипта при любой ошибке (не игнорировать exit code ≠ 0).

-u — ошибка при обращении к неинициализированной переменной (не будет пустых значений «по-тихому»).

-o pipefail — пайплайны возвращают код ошибки первой упавшей команды, а не последней.

По итогу:

  • Скрипт точно запустится под bash
  • Ошибки не будут замалчиваться
  • Сразу ловишь косяки

Удобно в CI/CD, где всё должно падать быстро и без хуйни.

grep foo file.txt | wc -l
echo $?   # 0, даже если grep ничего не нашёл
set -o pipefail
grep foo file.txt | wc -l
echo $?   # 1, потому что grep ушел по пизде

Такие дела, изучай.

Комментарии