我正在尝试编写一个小脚本来计算日志文件中的条目,并且我正在递增一个变量(
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
您在子 shell 中使用
USCOUNTER
,这就是变量未显示在主 shell 中的原因。
代替
cat FILE | while ...
,只做 while ... done < $FILE
。这样,您就可以避免常见问题:我在管道中的循环中设置变量。为什么循环结束后它们就消失了?或者,为什么我无法通过管道读取数据?:
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
包含剩余内容。
极简主义
counter=0
((counter++))
echo $counter
此方法使用此处定义的算术扩展:Bash Arithmetic Expansion
有效表达式在这里定义:Shell Arithmetic
-r
与 read 一起使用。cut
,您可以坚持使用纯bash解决方案。
read
第二个变量 (_
) 来捕获额外的“字段”[[ ]]
而不是 [ ]
。while read -r country _; do
if [[ $country = 'US' ]]; then
((USCOUNTER++))
echo "US counter $USCOUNTER"
fi
done < "$FILE"
您得到
final 0
是因为您的 while loop
正在子(shell)进程中执行,并且在那里所做的任何更改都不会反映在当前(父)shell 中。
正确的脚本:
while read -r country _; do
if [ "US" = "$country" ]; then
((USCOUNTER++))
echo "US counter $USCOUNTER"
fi
done < "$FILE"
我在 while 循环中遇到相同的 $count 变量丢失问题。
@fedorqui 的答案(以及其他一些)是对实际问题的准确答案:子 shell 确实是问题所在。
但这让我遇到了另一个问题:我不是通过管道传输文件内容...而是一系列管道和 grep 的输出...
我的错误示例代码:
count=0
cat /etc/hosts | head | while read line; do
((count++))
echo $count $line
done
echo $count
以及我的修复感谢该线程和进程替换的帮助:
count=0
while IFS= read -r line; do
((count++))
echo "$count $line"
done < <(cat /etc/hosts | head)
echo "$count"
USCOUNTER=$(grep -c "^US " "$FILE")
增加变量可以这样完成:
_my_counter=$[$_my_counter + 1]
可以使用 grep 来计算列中某个模式出现的次数
grep -cE "^([^ ]* ){2}US"
-c
数
([^ ]* )
检测结肠
{2}
结肠号
US
你的图案
使用以下 1 行命令使用短语特异性更改 Linux 中的许多文件名:
find -type f -name '*.jpg' | rename 's/holiday/honeymoon/'
对于所有扩展名为“.jpg”的文件,如果它们包含字符串“holiday”,请将其替换为“honeymoon”。例如,此命令会将文件“ourholiday001.jpg”重命名为“ourhoneymoon001.jpg”。
此示例还说明了如何使用 find 命令发送扩展名为 .jpg (-name '*.jpg') 的文件列表 (-type f),以通过管道 (|) 进行重命名。重命名然后从标准输入读取其文件列表。