Ответ 1
Как сделать цикл против stdin и получить результат, сохраненный в переменной
В bash (и другие shell также, когда вы что-то делаете, используя |
к другой команде, вы будете неявно создавать вилку, подоболочку, которая является дочерним элементом текущей сессии и которая не может повлиять на текущую среду сеанса.
Итак, это:
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
echo final total: $TOTAL
не даст ожидаемого результата!
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
echo final total: $TOTAL
final total: 0
Если вычисленный TOTAL не может быть повторно использован в главном script.
Инвертирование вилки
Используя bash Замена процесса, Здесь Documents или Here Strings вы можете инвертировать fork:
Здесь строки
read A B <<<"first second"
echo $A
first
echo $B
second
Здесь Документы
while read A B;do
echo $A-$B
C=$A-$B
done << eodoc
first second
third fourth
eodoc
first-second
third-fourth
вне цикла:
echo : $C
: third-fourth
Здесь Команды
TOTAL=0
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done < <(
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664
)
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
# and finally out of loop:
echo $TOTAL
-343
Теперь вы можете использовать $TOTAL
в своем основном script.
Подключение к списку команд
Но для работы только с stdin вы можете создать вид script в fork:
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 | {
TOTAL=0
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
echo "Out of the loop total:" $TOTAL
}
Дает:
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
Out of the loop total: -343
Примечание: $TOTAL
не может использоваться в основном script (после последней правой фигурной скобки }
).
Использование опции lastpipe bash
Как правильно указал @CharlesDuffy, существует опция bash, используемая для изменения этого поведения. Но для этого мы должны сначала отключить управление заданиями:
shopt -s lastpipe # Set *lastpipe* option
set +m # Disabling job control
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
9 - 4 = 5 -> TOTAL= -338
3 - 1 = 2 -> TOTAL= -336
77 - 2 = 75 -> TOTAL= -261
25 - 12 = 13 -> TOTAL= -248
226 - 664 = -438 -> TOTAL= -686
echo final total: $TOTAL
-343
Это будет работать, но мне (лично) это не нравится, потому что это не стандартное и не поможет сделать script доступным для чтения. Также отключить управление заданиями представляется дорогостоящим для доступа к этому поведению.
Примечание. Управление заданием включено по умолчанию только в интерактивных сеансах. Поэтому set +m
не требуется в обычных скриптах.
Итак, забытый set +m
в script создавал бы разные поведения, если они запускались в консоли или запускались в script. Это не поможет сделать это легко понять или отладить...