Увеличение счетчика в цикле Bash не работает
У меня есть следующий простой script, где я запускаю цикл и хочу поддерживать COUNTER
. Я не могу понять, почему счетчик не обновляется. Это связано с созданием подоболочки? Как я могу это исправить?
#!/bin/bash
WFY_PATH=/var/log/nginx
WFY_FILE=error.log
COUNTER=0
grep 'GET /log_' $WFY_PATH/$WFY_FILE | grep 'upstream timed out' | awk -F ', ' '{print $2,$4,$0}' | awk '{print "http://domain.com"$5"&ip="$2"&date="$7"&time="$8"&end=1"}' | awk -F '&end=1' '{print $1"&end=1"}' |
(
while read WFY_URL
do
echo $WFY_URL #Some more action
COUNTER=$((COUNTER+1))
done
)
echo $COUNTER # output = 0
Ответы
Ответ 1
Во-первых, вы не увеличиваете счетчик. Изменение COUNTER=$((COUNTER))
на COUNTER=$((COUNTER + 1))
или COUNTER=$[COUNTER + 1]
приведет к его увеличению.
Во-вторых, сложнее обменивать переменные подселей на вызывающую, как вы догадываетесь. Переменные в подоболочке недоступны вне подоболочки. Это переменные, локальные для дочернего процесса.
Один из способов его решения - использовать временный файл для хранения промежуточного значения:
TEMPFILE=/tmp/$$.tmp
echo 0 > $TEMPFILE
# Loop goes here
# Fetch the value and increase it
COUNTER=$[$(cat $TEMPFILE) + 1]
# Store the new value
echo $COUNTER > $TEMPFILE
# Loop done, script done, delete the file
unlink $TEMPFILE
Ответ 2
COUNTER=1
while [ Your != "done" ]
do
echo " $COUNTER "
COUNTER=$[$COUNTER +1]
done
TESTED BASH: Centos, SuSE, RH
Ответ 3
COUNTER=$((COUNTER+1))
- довольно неуклюжая конструкция в современном программировании.
(( COUNTER++ ))
выглядит более "современным". Вы также можете использовать
let COUNTER++
если вы считаете, что улучшает читаемость. Иногда Bash дает слишком много способов сделать что-то - философия Perl, я полагаю, когда возможно, что Python "есть только один правильный способ сделать это", может быть более уместным. Это дискуссионное выражение, если когда-либо было один! Во всяком случае, я бы предложил, чтобы цель (в данном случае) заключалась не только в том, чтобы увеличить переменную, но (общее правило), чтобы также написать код, который кто-то может понять и поддержать. Соответствие имеет большое значение для достижения этого.
НТН
Ответ 4
count=0
base=1
(( count += base ))
Ответ 5
Попробуйте использовать
COUNTER=$((COUNTER+1))
вместо
COUNTER=$((COUNTER))
Ответ 6
Я думаю, что этот единственный awk-вызов эквивалентен вашему конвейеру grep|grep|awk|awk
: пожалуйста, протестируйте его. Ваша последняя команда awk ничего не меняет.
Проблема с COUNTER заключается в том, что цикл while работает в подоболочке, поэтому любые изменения в переменной исчезают при выходе из подоболочки. Вам нужно получить доступ к значению COUNTER в той же подоболочке. Или возьмите совет @DennisWilliamson, используйте замену процесса и вообще избегайте подселочки.
awk '
/GET \/log_/ && /upstream timed out/ {
split($0, a, ", ")
split(a[2] FS a[4] FS $0, b)
print "http://example.com" b[5] "&ip=" b[2] "&date=" b[7] "&time=" b[8] "&end=1"
}
' | {
while read WFY_URL
do
echo $WFY_URL #Some more action
(( COUNTER++ ))
done
echo $COUNTER
}
Ответ 7
Вместо того, чтобы использовать временный файл, можно избежать создания подоболочки вокруг в while
цикла с помощью подстановки процесса.
while ...
do
...
done < <(grep ...)
Кстати, вы должны быть в состоянии преобразовать все эти grep, grep, awk, awk, awk
в один awk
.
Начиная с Bash 4.2, существует опция lastpipe
которая
запускает последнюю команду конвейера в текущем контексте оболочки. Параметр lastpipe не действует, если включен контроль заданий.
bash -c 'echo foo | while read -r s; do c=3; done; echo "$c"'
bash -c 'shopt -s lastpipe; echo foo | while read -r s; do c=3; done; echo "$c"'
3
Ответ 8
минималистский
counter=0
((counter++))
echo $counter
Ответ 9
Это все, что вам нужно сделать:
$((COUNTER++))
Вот выдержка из изучения bash Shell, 3-е издание, стр. 147, 148:
bash арифметические выражения эквивалентны их аналогам в языки Java и C. [9] Приоритет и ассоциативность одинаковы как в C. Таблица 6-2 показывает поддерживаемые арифметические операторы. Хотя некоторые из них (или содержат) специальные символы, есть не нужно обратная косая черта - избегать их, потому что они находятся в пределах $((...)) синтаксис.
..........................
Операторы ++ и - полезны, когда вы хотите увеличить или уменьшить значение на единицу. [11] Они работают так же, как в Java и C, например, значение ++ увеличивает значение на 1. Это называется post-increment; существует также значение pre-increment: ++. Различие становится очевидным с примером:
$ i=0
$ echo $i
0
$ echo $((i++))
0
$ echo $i
1
$ echo $((++i))
2
$ echo $i
2
См. http://www.safaribooksonline.com/a/learning-the-bash/7572399/
Ответ 10
Кажется, что вы не обновили counter
, это script, используйте counter++