programing

Bash 루프의 카운터 증분이 작동하지 않음

lastmoon 2023. 4. 22. 10:02
반응형

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.example"$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

째,, 카카를를 늘늘다다다다「」의 변경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
COUNTER=1
while [ Your != "done" ]
do
     echo " $COUNTER "
     COUNTER=$[$COUNTER +1]
done

테스트 완료 BASH: Centos, SuSE, RH

COUNTER=$((COUNTER+1)) 

현대 프로그래밍에서는 꽤 서투른 구성입니다.

(( COUNTER++ ))

좀 더 '현대적'인 것 같아요.를 사용할 수도 있습니다.

let COUNTER++

가독성이 향상된다고 생각하시면요.Python이 "올바른 방법은 하나밖에 없다"고 하는 것이 더 적절할 때 Bash는 Perl 철학에 너무 많은 방법을 너무 많이 제시합니다.그것은 논란의 여지가 있는 진술이다.어쨌든 (이 경우) 단순히 변수를 늘리는 것이 아니라 다른 사람이 이해하고 지원할 수 있는 코드를 작성하는 것이 목적입니다.순응은 그것을 달성하는 데 큰 도움이 된다.

HTH

사용해보십시오.

COUNTER=$((COUNTER+1))

대신

COUNTER=$((COUNTER))

은 당신의 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
}
count=0   
base=1
(( count += base ))

파일을 하는 것이 , 파일 됩니다.while이치노

while ...
do
   ...
done < <(grep ...)

그 모든 수 예요.grep, grep, awk, awk, awk가 되어awk.

4부터는 Bash 4.2가 .lastpipeoption 'so' ()

는 현재 셸 컨텍스트에서 파이프라인의 마지막 명령을 실행합니다.작업 제어를 사용하도록 설정한 경우 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

미니멀리스트

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

이 표현은 두 가지 조건이 있습니다.((var++))실패하기 위해:

  1. bash를 strict 모드로 설정했을 경우(set -euo pipefail(0부터 증가)를 시작합니다.

  2. 1부터 시작하는 것은 괜찮지만 0부터 시작하는 것은 "+"를 평가할 때 증가분이 "1"을 반환합니다.이것은 엄밀한 모드에서 0이 아닌 리턴 코드 장애입니다.

사용할 수 있습니다.((var+=1))또는var=$((var+1))이 행동에서 벗어나기 위해

이것으로 충분합니다.

$((COUNTER++))

다음은 Learning the bash Shell, 제3판, 147, 148페이지에서 발췌한 것입니다.

bash 산술식은 Java 및 C 언어의 산술식과 동일합니다.[9] 우선순위 및 연관성은 C와 동일합니다.표 6-2는 지원되는 산술 연산자를 보여줍니다.이들 중 일부는 특수문자(또는 포함)이지만 $(...) 구문 내에 있으므로 백슬래시를 이스케이프할 필요가 없습니다.

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

++ 및 - 연산자는 값을 1씩 늘리거나 줄이려는 경우에 유용합니다.[11] Java 및 C와 동일하게 동작합니다.예를 들어 value++는 을 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/ 를 참조해 주세요.

이것은 간단한 예시입니다.

COUNTER=1
for i in {1..5}
do   
   echo $COUNTER;
   //echo "Welcome $i times"
   ((COUNTER++));    
done

소스 스크립트에 하위 셸에 문제가 있습니다.첫 번째 예에서는 서브셸이 필요하지 않을 수 있습니다.근데 'Some more action' 밑에 뭐가 숨겨져 있는지 모르겠어요.가장 일반적인 답변은 I/O를 증가시키는 숨겨진 버그가 있으며, 서브셸에서는 작동하지 않습니다. 왜냐하면 루프 내부에서 쿠터를 복원하기 때문입니다.

'\' 기호를 추가하지 마십시오. bash 인터프리터에 회선 연속에 대해 알려줍니다.당신이나 누구에게도 도움이 되길 바랍니다.단, 이 스크립트는 AWK 스크립트로 완전히 변환하거나 regexp 또는 perl을 사용하여 python으로 다시 작성해야 하지만 perl의 인기는 수년간 저하되고 있습니다.비단뱀으로 하는 게 좋을 거야

수정 버전(서브셸 제외):

#!/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://example.com"$5"&ip="$2"&date="$7"&time="$8"&end=1"}' |\
awk -F '&end=1' '{print $1"&end=1"}' |\
#(  #unneeded bracket
while read WFY_URL
do
    echo $WFY_URL #Some more action
    COUNTER=$((COUNTER+1))
done
# ) unneeded bracket

echo $COUNTER # output = 0

꼭 필요한 경우 하위 셸이 포함된 버전

#!/bin/bash

TEMPFILE=/tmp/$$.tmp  #I've got it from the most popular answer
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://example.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 > $TEMPFILE  #store counter only once, do it after loop, you will save I/O
)

COUNTER=$(cat $TEMPFILE)  #restore counter
unlink $TEMPFILE
echo $COUNTER # output = 0

업데이트하지 않은 것 같습니다.counter스크립트입니다.사용counter++

언급URL : https://stackoverflow.com/questions/10515964/counter-increment-in-bash-loop-not-working

반응형