lastpipe: как Bash меняет поведение последней команды в pipeline
Одна из особенностей Bash - команды в pipeline обычно выполняются в отдельных subshell. Из-за этого переменные, изменённые внутри while, после цикла могут не сохраниться.
Например:
count=0
printf '%s\n' a b c |
while read -r line; do
((count++))
done
echo "$count"
В некоторых случаях результатом будет 0.
Но у Bash есть настройка lastpipe, которая меняет это поведение.
▪️Включаем lastpipe
shopt -s lastpipe
Теперь последняя команда pipeline может выполняться в текущем shell.
count=0
printf '%s\n' a b c |
while read -r line; do
((count++))
done
echo "$count"
При подходящих условиях получим: 3
▪️Есть важное условие
lastpipe работает только когда job control отключён:
set +m
shopt -s lastpipe
Именно поэтому поведение может отличаться между интерактивным Bash и обычным скриптом.
▪️Проверить настройку
shopt lastpipe
Получим:
lastpipe off
или:
lastpipe on
▪️Почему это не универсальная замена
Вместо изменения поведения shell часто проще использовать редирект:
while read -r line; do
((count++))
done <
Одна из особенностей Bash - команды в pipeline обычно выполняются в отдельных subshell. Из-за этого переменные, изменённые внутри while, после цикла могут не сохраниться.
Например:
count=0
printf '%s\n' a b c |
while read -r line; do
((count++))
done
echo "$count"
В некоторых случаях результатом будет 0.
Но у Bash есть настройка lastpipe, которая меняет это поведение.
▪️Включаем lastpipe
shopt -s lastpipe
Теперь последняя команда pipeline может выполняться в текущем shell.
count=0
printf '%s\n' a b c |
while read -r line; do
((count++))
done
echo "$count"
При подходящих условиях получим: 3
▪️Есть важное условие
lastpipe работает только когда job control отключён:
set +m
shopt -s lastpipe
Именно поэтому поведение может отличаться между интерактивным Bash и обычным скриптом.
▪️Проверить настройку
shopt lastpipe
Получим:
lastpipe off
или:
lastpipe on
▪️Почему это не универсальная замена
Вместо изменения поведения shell часто проще использовать редирект:
while read -r line; do
((count++))
done <