[英]Incrementing a variable inside a Bash loop
I'm trying to write a small script that will count entries in a log file, and I'm incrementing a variable ( USCOUNTER
) which I'm trying to use after the loop is done. 我正在尝试编写一个
USCOUNTER
计算日志文件中的条目,我正在递增一个变量( USCOUNTER
),我在循环完成后尝试使用它。
But at that moment USCOUNTER
looks to be 0 instead of the actual value. 但在那一刻,
USCOUNTER
看起来是0而不是实际价值。 Any idea what I'm doing wrong? 知道我做错了什么吗? Thanks!
谢谢!
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"
It outputs: 它输出:
US counter 1
US counter 2
US counter 3
..
final 0
You are using USCOUNTER
in a subshell, that's why the variable is not showing in the main shell. 您在子shell中使用
USCOUNTER
,这就是变量未在主shell中显示的原因。
Instead of cat FILE | while ...
而不是
cat FILE | while ...
cat FILE | while ...
, do just a while ... done < $FILE
. cat FILE | while ...
,做while ... done < $FILE
。 This way, you avoid the common problem of 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"
Note I also replaced the `` expression with a $(). 注意我也用$()替换了``表达式。
I also replaced while read line; do country=$(echo "$line" | cut -d' ' -f1)
我也在
while read line; do country=$(echo "$line" | cut -d' ' -f1)
更换了while read line; do country=$(echo "$line" | cut -d' ' -f1)
while read line; do country=$(echo "$line" | cut -d' ' -f1)
with while read country _
. while read line; do country=$(echo "$line" | cut -d' ' -f1)
with while read country _
。 This allows you to say while read var1 var2 ... varN
where var1
contains the first word in the line, $var2
and so on, until $varN
containing the remaining content. 这允许您
while read var1 var2 ... varN
说明var1
包含行中的第一个单词$var2
,依此类推,直到$varN
包含剩余内容。
-r
with read . -r
with read 。 cut
, you can stick with pure bash solutions. cut
,你可以坚持使用纯粹的bash解决方案。
read
a 2nd var ( _
) to catch the additional "fields" read
第二个var( _
)以捕获其他“字段” [[ ]]
over [ ]
. [[ ]]
不是[ ]
。 while read -r country _; do
if [[ $country = 'US' ]]; then
((USCOUNTER++))
echo "US counter $USCOUNTER"
fi
done < "$FILE"
minimalist 极简主义
counter=0
((counter++))
echo $counter
You're getting final 0
because your while loop
is being executed in a sub (shell) process and any changes made there are not reflected in the current (parent) shell. 你得到的是
final 0
因为你的while loop
正在子(shell)进程中执行,并且那里所做的任何更改都没有反映在当前(父)shell中。
Correct script: 正确的脚本:
while read -r country _; do
if [ "US" = "$country" ]; then
((USCOUNTER++))
echo "US counter $USCOUNTER"
fi
done < "$FILE"
I had the same $count variable in a while loop getting lost issue. 我在while循环中遇到了相同的$ count变量。
@fedorqui's answer (and a few others) are accurate answers to the actual question: the sub-shell is indeed the problem. @ fedorqui的答案 (以及其他几个)是对实际问题的准确答案:子shell确实是问题所在。
But it lead me to another issue: I wasn't piping a file content... but the output of a series of pipes & greps... 但它引出了另一个问题:我没有管道文件内容...但是输出了一系列的管道和greps ......
my erroring sample code: 我的错误示例代码:
count=0
cat /etc/hosts | head | while read line; do
((count++))
echo $count $line
done
echo $count
and my fix thanks to the help of this thread and the process substitution : 感谢这个线程的帮助和进程替换 :
count=0
while IFS= read -r line; do
((count++))
echo "$count $line"
done < <(cat /etc/hosts | head)
echo "$count"
USCOUNTER=$(grep -c "^US " "$FILE")
Incrementing a variable can be done like that: 增量变量可以这样做:
_my_counter=$[$_my_counter + 1]
Counting the number of occurrence of a pattern in a column can be done with grep 计算列中模式的出现次数可以使用grep来完成
grep -cE "^([^ ]* ){2}US"
-c
count -c
计数
([^ ]* )
To detect a colonne ([^ ]* )
检测结肠
{2}
the colonne number {2}
结肠数
US
your pattern US
你的模式
Using the following 1 line command for changing many files name in linux using phrase specificity: 使用以下1行命令在linux中使用短语特征更改许多文件名:
find -type f -name '*.jpg' | rename 's/holiday/honeymoon/'
For all files with the extension ".jpg", if they contain the string "holiday", replace it with "honeymoon". 对于扩展名为“.jpg”的所有文件,如果它们包含字符串“holiday”,请将其替换为“honeymoon”。 For instance, this command would rename the file "ourholiday001.jpg" to "ourhoneymoon001.jpg".
例如,此命令会将文件“ourholiday001.jpg”重命名为“ourhoneymoon001.jpg”。
This example also illustrates how to use the find command to send a list of files (-type f) with the extension .jpg (-name '*.jpg') to rename via a pipe (|). 此示例还说明了如何使用find命令发送扩展名为.jpg(-name'* .jpg')的文件列表(-type f),以通过管道(|)重命名。 rename then reads its file list from standard input.
然后重命名从标准输入读取其文件列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.