Spa*_*pta 117 linux bash shell scripting counter
我有以下简单的脚本,我正在运行一个循环,并希望维护一个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 $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
Run Code Online (Sandbox Code Playgroud)
bos*_*bos 155
首先,你没有增加柜台.更改COUNTER=$((COUNTER))成COUNTER=$((COUNTER + 1))或COUNTER=$[COUNTER + 1]将增加它.
其次,当你猜测时,将子shell变量反向传播给被调用者是很棘手的.子shell外部不提供子shell中的变量.这些是子进程的本地变量.
解决它的一种方法是使用临时文件来存储中间值:
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
Run Code Online (Sandbox Code Playgroud)
小智 85
COUNTER=1
while [ Your != "done" ]
do
echo " $COUNTER "
COUNTER=$[$COUNTER +1]
done
Run Code Online (Sandbox Code Playgroud)
测试BASH:Centos,SuSE,RH
小智 39
COUNTER=$((COUNTER+1))
Run Code Online (Sandbox Code Playgroud)
在现代编程中是一个非常笨拙的结构.
(( COUNTER++ ))
Run Code Online (Sandbox Code Playgroud)
看起来更"现代".你也可以使用
let COUNTER++
Run Code Online (Sandbox Code Playgroud)
如果你认为这提高了可读性.有时,Bash提供了太多的做事方式 - 我认为Perl哲学 - 也许Python"只有一种正确的方法"可能更合适.如果有的话,这是一个值得商榷的陈述!无论如何,我建议目标(在这种情况下)不仅仅是增加变量,而是(一般规则)也编写其他人可以理解和支持的代码.符合性对实现这一点有很大帮助.
HTH
dbf*_*dbf 13
尝试使用
COUNTER=$((COUNTER+1))
Run Code Online (Sandbox Code Playgroud)
代替
COUNTER=$((COUNTER))
Run Code Online (Sandbox Code Playgroud)
gle*_*man 11
我认为这个单独的awk调用等同于你的grep|grep|awk|awk管道:请测试它.你的上一个awk命令似乎什么都没改变.
COUNTER的问题是while循环在子shell中运行,因此当subshell退出时,对变量的任何更改都会消失.您需要在相同的子shell中访问COUNTER的值.或者采取@ DennisWilliamson的建议,使用流程替换,并完全避免子shell.
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
}
Run Code Online (Sandbox Code Playgroud)
您可以while通过使用进程替换来避免在循环周围创建子shell,而不是使用临时文件.
while ...
do
...
done < <(grep ...)
Run Code Online (Sandbox Code Playgroud)
顺便说一下,你应该能够把所有这些grep, grep, awk, awk, awk变成一个单一的awk.
从Bash 4.2开始,有一个lastpipe选项
在当前shell上下文中运行管道的最后一个命令.如果启用了作业控制,则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
Run Code Online (Sandbox Code Playgroud)
极简主义
counter=0
((counter++))
echo $counter
Run Code Online (Sandbox Code Playgroud)
小智 7
有两个条件导致((var++))我的表达失败:
如果我将 bash 设置为严格模式( set -euo pipefail) 并且如果我从零(0) 开始增量。
从一 (1) 开始很好,但零会导致在评估“++”时增量返回“1”,这在严格模式下是非零返回代码失败。
我可以使用((var+=1))或var=$((var+1))逃避这种行为