Подводные камни в Bash №7
Продолжаем делать правильно.
читать первым в телеграм читать первым в макс
Этот код выглядит вполне нормально:
grep foo bar.txt | while read -r; do ((count++)); done
Он считает, сколько строк в файле bar.txt содержат слово foo.
Здесь главная проблема — переменная count не изменится вне цикла while, потому что в Bash каждая команда в пайплайне (|) запускается в отдельной оболочке (subshell). То есть count++ происходит «внутри», и снаружи этого не видно.
Если простым языком: Каждая часть, разделённая |, запускается в отдельной «коробке» (subshell). То есть while работает внутри своей коробки. B всё что там происходит, не видно снаружи.
count=0
echo -e "one\ntwo\nthree" | while read line; do ((count++)); done
echo $count
Этот код вернет 0, несмотря на count++, а вот например в zsh вернется 3.
Как быть?
Первый вариант:
shopt -s lastpipe
Эта штука говорит интерпретатору — сделай всё сам и не передавай работу другому.
Второй вариант:
Вообще избавиться от while и всё сделать через grep:
count=$(grep -c foo bar)
echo $count
Выводы
Нужно просто посчитать строки:
count=$(grep -c foo bar)
Нужно обрабатывать строки:
while read line; do ...; done < bar
Хочешь использовать pipe:
shopt -s lastpipe
Вот и вся наука.
