【问题标题】:Incrementing a variable inside a Bash loop在 Bash 循环中增加变量
【发布时间】:2014-01-07 23:49:39
【问题描述】:

我正在尝试编写一个小脚本来计算日志文件中的条目,并且我正在增加一个变量 (USCOUNTER),我正在尝试在循环完成后使用该变量。

但在那一刻USCOUNTER 看起来是 0 而不是实际值。知道我做错了什么吗?谢谢!

FILE=$1

tail -n10 mylog > $FILE

USCOUNTER=0

cat $FILE | while read line; do
  country=$(echo "$line" | cut -d' ' -f1)
  if [ "US" = "$country" ]; then
        USCOUNTER=`expr $USCOUNTER + 1`
        echo "US counter $USCOUNTER"
  fi
done
echo "final $USCOUNTER"

它输出:

US counter 1
US counter 2
US counter 3
..
final 0

【问题讨论】:

标签: bash shell loops


【解决方案1】:

您在子 shell 中使用 USCOUNTER,这就是变量未显示在主 shell 中的原因。

不要使用cat FILE | while ...,而是使用while ... done < $FILE。这样就避免了I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?的常见问题:

while read country _; do
  if [ "US" = "$country" ]; then
        USCOUNTER=$(expr $USCOUNTER + 1)
        echo "US counter $USCOUNTER"
  fi
done < "$FILE"

注意,我还用 $() 替换了 `` 表达式。

我还将while read line; do country=$(echo "$line" | cut -d' ' -f1) 替换为while read country _。这允许您说while read var1 var2 ... varN,其中var1 包含该行中的第一个单词,$var2 等等,直到$varN 包含其余内容。

【讨论】:

  • 请注意,您可以使用 $(($USCOUNTER+1)) 来计算表达式
  • 谢谢@geert3,很好。同样((USCOUNTER++)) 作为anubhava 的解决方案正在使用。如果它与 OPs shell 不兼容,我不会将其添加到我的答案中。
【解决方案2】:

您收到final 0 是因为您的while loop 正在子(shell)进程中执行,并且在那里所做的任何更改都不会反映在当前(父)shell 中。

正确的脚本:

while read -r country _; do
  if [ "US" = "$country" ]; then
        ((USCOUNTER++))
        echo "US counter $USCOUNTER"
  fi
done < "$FILE"

【讨论】:

    【解决方案3】:
    while read -r country _; do
      if [[ $country = 'US' ]]; then
        ((USCOUNTER++))
        echo "US counter $USCOUNTER"
      fi
    done < "$FILE"
    

    【讨论】:

    • 为什么不在 if 中echo "US counter $((USCOUNTER++))"
    • @KrzysztofJabłoński 如果您希望它与上面的代码等效,那么您应该使用"US counter $((++USCOUNTER))"。这是一个很好的观点,你是对的!
    【解决方案4】:
    USCOUNTER=$(grep -c "^US " "$FILE")
    

    【讨论】:

      【解决方案5】:

      极简主义

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

      【讨论】:

      • 一些解释将不胜感激
      • 您的示例中想要的 while 循环在哪里?
      【解决方案6】:

      增加一个变量可以这样完成:

        _my_counter=$[$_my_counter + 1]
      

      可以用 grep 计算列中模式出现的次数

       grep -cE "^([^ ]* ){2}US"
      

      -c计数

      ([^ ]* )检测冒号

      {2}冒号

      US你的模式

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关 why 和/或 如何 回答问题的额外上下文将显着改善其长期价值。请edit你的答案添加一些解释。
      • 标题是:“Bash 在循环中递增变量”我的行是:“在 bash 中递增变量”所以我认为它确实回答了部分问题(至少与来自geekzspot)
      • 算术扩展的$[ ... ] 语法是deprecated。请改用$(( ... ))。您的答案和 geekzspot 都解决了 OP 问题的一个 偶然 方面,该方面不能解决问题(OP 代码的变量递增部分正在工作(但效率低下))。如果您想在不回答问题的情况下提出附带的改进建议,请明确说明。
      【解决方案7】:

      我在 while 循环中遇到了相同的 $count 变量丢失问题。

      @fedorqui's answer(和其他一些人)是对实际问题的准确答案:子外壳确实是问题所在。

      但这导致我遇到另一个问题:我不是管道文件内容...而是一系列管道和 grep 的输出...

      我的错误示​​例代码:

      count=0
      cat /etc/hosts | head | while read line; do
        ((count++))
        echo $count $line
      done
      echo $count
      

      感谢这个帖子和process substitution

      count=0
      while IFS= read -r line; do
        ((count++))
        echo "$count $line"
      done < <(cat /etc/hosts | head)
      echo "$count"
      

      【讨论】:

      • 很高兴看到我的回答很有帮助 :) 另请注意,cat file | head 可以简化为 head file
      【解决方案8】:

      使用以下 1 行命令在 linux 中使用短语特异性更改许多文件名:

      find -type f -name '*.jpg' | rename 's/holiday/honeymoon/'
      

      对于所有扩展名为“.jpg”的文件,如果它们包含字符串“holiday”,则将其替换为“honeymoon”。例如,此命令会将文件“ourholiday001.jpg”重命名为“ourhoneymoon001.jpg”。

      此示例还说明了如何使用 find 命令通过管道 (|) 发送扩展名为 .jpg (-name '*.jpg') 的文件列表 (-type f) 以重命名。 rename 然后从标准输入中读取其文件列表。

      【讨论】:

        猜你喜欢
        • 2015-05-10
        • 2020-05-26
        • 2013-01-16
        • 2013-11-25
        • 2014-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-26
        相关资源
        最近更新 更多