Linux Bash循环中的计数器增量不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10515964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 06:14:49  来源:igfitidea点击:

Counter increment in Bash loop not working

linuxbashshellscriptingcounter

提问by Sparsh Gupta

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 due to subshell thats getting created? How can I potentially fix this?

我有以下简单的脚本,我在其中运行一个循环并希望维护一个COUNTER. 我无法弄清楚为什么计数器没有更新。是因为创建了子shell吗?我怎样才能解决这个问题?

#!/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 ,,
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
}' | awk '{print "http://domain.com""&ip=""&date=""&time=""&end=1"}' | awk -F '&end=1' '{print "&end=1"}' | ( while read WFY_URL do echo $WFY_URL #Some more action COUNTER=$((COUNTER+1)) done ) echo $COUNTER # output = 0

采纳答案by bos

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

首先,您没有增加计数器。更改COUNTER=$((COUNTER))COUNTER=$((COUNTER + 1))COUNTER=$[COUNTER + 1]将增加它。

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.

其次,正如您猜测的那样,将子shell 变量反向传播到被调用者会更棘手。子外壳中的变量在子外壳之外不可用。这些是子进程的局部变量。

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

解决它的一种方法是使用临时文件来存储中间值:

COUNTER=$((COUNTER+1))

回答by dbf

Try to use

尝试使用

COUNTER=$((COUNTER))

instead of

代替

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

回答by yjshen

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

看来你没有更新counter是脚本,使用counter++

回答by Paused until further notice.

Instead of using a temporary file, you can avoid creating a subshell around the whileloop by using process substitution.

您可以while通过使用进程替换来避免在循环周围创建子shell,而不是使用临时文件。

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

By the way, you should be able to transform all that grep, grep, awk, awk, awkinto a single awk.

顺便说一句,您应该能够将所有这些grep, grep, awk, awk, awk转换为单个awk.

Starting with Bash 4.2, there is a lastpipeoption that

从 Bash 4.2 开始,有一个lastpipe选项

runs the last command of a pipeline in the current shell context. The lastpipe option has no effect if job control is enabled.

在当前 shell 上下文中运行管道的最后一个命令。如果启用了作业控制,则 lastpipe 选项无效。

awk '
  /GET \/log_/ && /upstream timed out/ {
    split(
COUNTER=1
while [ Your != "done" ]
do
     echo " $COUNTER "
     COUNTER=$[$COUNTER +1]
done
, a, ", ") split(a[2] FS a[4] FS
count=0   
base=1
(( count += base ))
, 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 }

回答by glenn Hymanman

I think this single awk call is equivalent to your grep|grep|awk|awkpipeline: please test it. Your last awk command appears to change nothing at all.

我认为这个单一的 awk 调用相当于您的grep|grep|awk|awk管道:请测试它。您的最后一个 awk 命令似乎没有任何改变。

The problem with COUNTER is that the while loop is running in a subshell, so any changes to the variable vanish when the subshell exits. You need to access the value of COUNTER in that same subshell. Or take @DennisWilliamson's advice, use a process substitution, and avoid the subshell altogether.

COUNTER 的问题在于while 循环在子shell 中运行,因此当子shell 退出时,对变量的任何更改都会消失。您需要在同一个子 shell 中访问 COUNTER 的值。或者接受@DennisWilliamson 的建议,使用进程替换,并完全避免使用子shell。

COUNTER=$((COUNTER+1)) 

回答by Jay Stan

(( COUNTER++ ))

TESTED BASH: Centos, SuSE, RH

测试 BASH:Centos、SuSE、RH

回答by pkm

let COUNTER++

回答by Bill Parker

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

is quite a clumsy construct in modern programming.

在现代编程中是一个相当笨拙的结构。

$((COUNTER++))

looks more "modern". You can also use

看起来更“现代”。你也可以使用

$ i=0
$ echo $i
0
$ echo $((i++))
0
$ echo $i
1
$ echo $((++i))
2
$ echo $i
2

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.

如果您认为这可以提高可读性。有时,Bash 提供了太多的做事方式——我想是 Perl 哲学——也许 Python “只有一种正确的方法可以做到这一点”可能更合适。如果有的话,这是一个值得商榷的声明!无论如何,我建议目标(在这种情况下)不仅仅是增加一个变量,而是(一般规则)还要编写其他人可以理解和支持的代码。一致性对实现这一目标大有帮助。

HTH

HTH

回答by geekzspot

minimalist

极简主义者

##代码##

回答by C.E. Montijo

This is all you need to do:

这就是您需要做的所有事情:

##代码##

Here's an excerpt from Learning the bash Shell, 3rd Edition, pp. 147, 148:

以下是Learning the bash Shell,第 3 版,第 147、148 页的摘录:

basharithmetic expressions are equivalent to their counterparts in the Java and C languages.[9] Precedence and associativity are the same as in C. Table 6-2 shows the arithmetic operators that are supported. Although some of these are (or contain) special characters, there is no need to backslash-escape them, because they are within the $((...)) syntax.

bash算术表达式等效于它们在 Java 和 C 语言中的对应项。 [9] 优先级和结合性与 C 中的相同。表 6-2 显示了支持的算术运算符。尽管其中一些是(或包含)特殊字符,但不需要反斜杠转义它们,因为它们在 $((...)) 语法中。

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

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

The ++ and - operators are useful when you want to increment or decrement a value by one.[11] They work the same as in Java and C, e.g., value++ increments value by 1. This is called post-increment; there is also a pre-increment: ++value. The difference becomes evident with an example:

++ 和 - 运算符在您希望将值递增或递减 1 时很有用。 [11] 它们的工作方式与 Java 和 C 中的相同,例如,value++ 将 value 增加 1。这称为post-increment;还有一个预增量:++。举个例子,区别就很明显了:

##代码##

See http://www.safaribooksonline.com/a/learning-the-bash/7572399/

http://www.safaribooksonline.com/a/learning-the-bash/7572399/