it-roy-ru.com

Увеличение счетчика в цикле Bash не работает

У меня есть следующий простой скрипт, где я запускаю цикл и хочу сохранить 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
111
Sparsh Gupta

Во-первых, вы не увеличиваете счетчик. Изменение COUNTER=$((COUNTER)) на COUNTER=$((COUNTER + 1)) или COUNTER=$[COUNTER + 1] увеличит его.

Во-вторых, сложнее передать обратно переменные subshell в вызываемую информацию, как вы и предполагаете. Переменные в подоболочке недоступны за пределами подоболочки. Это переменные, локальные для дочернего процесса.

Один из способов решить эту проблему - использовать временный файл для хранения промежуточного значения:

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
151
bos
COUNTER=1
while [ Your != "done" ]
do
     echo " $COUNTER "
     COUNTER=$[$COUNTER +1]
done

ИСПЫТАННЫЕ BASH: Centos, SuSE, RH

83
Jay Stan
COUNTER=$((COUNTER+1)) 

довольно неуклюжая конструкция в современном программировании.

(( COUNTER++ ))

выглядит более "современно". Вы также можете использовать

let COUNTER++

если вы думаете, что улучшает читабельность. Иногда Bash предлагает слишком много способов сделать что-то - я полагаю, философия Perl - когда, возможно, более подходящим может быть Python "есть только один правильный способ сделать это". Это спорное утверждение, если когда-либо был один! В любом случае, я хотел бы предложить цель (в данном случае) не просто увеличить переменную, а (общее правило) также написать код, который кто-то может понять и поддержать. Соответствие имеет большое значение для достижения этого.

НТН

36
Bill Parker
count=0   
base=1
(( count += base ))
13
pkm

Попробуй использовать

COUNTER=$((COUNTER+1))

вместо

COUNTER=$((COUNTER))
12
dbf

Я думаю, что этот единственный вызов 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
}
10
glenn jackman

Вместо использования временного файла вы можете избежать создания подоболочки вокруг цикла 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
Dennis Williamson

минималист

counter=0
((counter++))
echo $counter
5
geekzspot

Это все, что вам нужно сделать:

$((COUNTER++))

Вот выдержка из изучения оболочки bash , 3-е издание, стр. 147, 148:

bash арифметические выражения эквивалентны их аналогам в языках Java и ​​C. [9] Приоритет и ассоциативность такие же, как в C. В таблице 6-2 показаны поддерживаемые арифметические операторы. Хотя некоторые из них являются (или содержат) специальные символы, нет необходимости их экранировать от обратной косой черты, поскольку они находятся в синтаксисе $ ((...)).

..........................

Операторы ++ и - полезны, когда вы хотите увеличить или уменьшить значение на единицу. [11] Они работают так же, как в Java и ​​C, например, значение ++ увеличивает значение на 1. Это называется пост-инкремент ; также есть предварительное увеличение : ++ значение . Разница становится очевидной на примере:

$ 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/

4
C.E. Montijo

Похоже, вы не обновили counter скрипт, используйте counter++

0
yjshen