Counter increment in Bash loop not working

前端 未结 13 2249
庸人自扰
庸人自扰 2020-12-02 05:31

I have the following simple script where I am running a loop and want to maintain a COUNTER. I am unable to figure out why the counter is not updating. Is it du

相关标签:
13条回答
  • 2020-12-02 06:17

    It seems that you didn't update the counter is the script, use counter++

    0 讨论(0)
  • 2020-12-02 06:20

    Source script has some problem with subshell. First example, you probably do not need subshell. But We don't know what is hidden under "Some more action". The most popular answer has hidden bug, that will increase I/O, and won't work with subshell, because it restores couter inside loop.

    Do not fortot add '\' sign, it will inform bash interpreter about line continuation. I hope it will help you or anybody. But in my opinion this script should be fully converted to AWK script, or else rewritten to python using regexp, or perl, but perl popularity over years is degraded. Better do it with python.

    Corrected Version without subshell:

    #!/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
    

    Version with subshell if it is really needed

    #!/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
    
    0 讨论(0)
  • 2020-12-02 06:22

    First, you are not increasing the counter. Changing COUNTER=$((COUNTER)) into COUNTER=$((COUNTER + 1)) or COUNTER=$[COUNTER + 1] will increase it.

    Second, it's trickier to back-propagate subshell variables to the callee as you surmise. Variables in a subshell are not available outside the subshell. These are variables local to the child process.

    One way to solve it is using a temp file for storing the intermediate value:

    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
    
    0 讨论(0)
  • 2020-12-02 06:30

    There were two conditions that caused the expression ((var++)) to fail for me:

    1. If I set bash to strict mode (set -euo pipefail) and if I start my increment at zero (0).

    2. Starting at one (1) is fine but zero causes the increment to return "1" when evaluating "++" which is a non-zero return code failure in strict mode.

    I can either use ((var+=1)) or var=$((var+1)) to escape this behavior

    0 讨论(0)
  • 2020-12-02 06:32
    COUNTER=$((COUNTER+1)) 
    

    is quite a clumsy construct in modern programming.

    (( COUNTER++ ))
    

    looks more "modern". You can also use

    let COUNTER++
    

    if you think that improves readability. Sometimes, Bash gives too many ways of doing things - Perl philosophy I suppose - when perhaps the Python "there is only one right way to do it" might be more appropriate. That's a debatable statement if ever there was one! Anyway, I would suggest the aim (in this case) is not just to increment a variable but (general rule) to also write code that someone else can understand and support. Conformity goes a long way to achieving that.

    HTH

    0 讨论(0)
  • 2020-12-02 06:33

    This is a simple example

    COUNTER=1
    for i in {1..5}
    do   
       echo $COUNTER;
       //echo "Welcome $i times"
       ((COUNTER++));    
    done
    
    0 讨论(0)
提交回复
热议问题