超出周期定义的变量的值从循环中消失

时间:2015-06-04 08:03:58

标签: bash variables

cd /var/log
grep "UFW BLOCK" syslog | cut -d ' ' -f 13 | sort -u > pippo.txt
k=0
i=1
ip=""
cat pippo.txt | while read line
do
   (( k += i ))
   ip=${line:4}
   echo "IP " $ip" added to list."
   echo -n "K="
   echo $k
   ufw deny from $ip > /dev/null
done
echo -n "Processed and added  "
echo "$k"
echo " IP via UFW to the firewall."

为什么k变量将保留在> cicle然后它松散了? 在 while - done 期间,cicle echo打印出正确的k值,但在cicle之外,在完成行之后,k始终打印为零。

2 个答案:

答案 0 :(得分:1)

这是因为管道|创建了一个子shell。

子shell复制当前环境并在其中运行新代码。

cd /var/log
grep "UFW BLOCK" syslog | cut -d ' ' -f 13 | sort -u > pippo.txt
k=0
i=1
ip=""
# Pipe creates an environment of its own with k=0, i=1 and ip=""
cat pippo.txt | while read line
do
    # The subshell increments its own version of k
    (( k += i ))
    ip=${line:4}
    echo "IP " $ip" added to list."
    echo -n "K="
    echo $k
    ufw deny from $ip > /dev/null
done
# Subhell no longer exists
echo -n "Processed and added  "
# The prior environment prints its version of k which is 0
echo "$k"
echo " IP via UFW to the firewall."

您可以通过删除管道并执行此操作来轻松解决此问题。

while read line
do
    (( k += i ))
    ip=${line:4}
    echo "IP " $ip" added to list."
    echo -n "K="
    echo $k
    ufw deny from $ip > /dev/null
done < pippo.txt

这应该会给你相同的效果,但是把它留在同一个shell中

迷你示例

您可以通过运行以下 one liner

来查看此子shell行为的效果
k=0; echo $( (( k++ )); echo $k ); echo $k

打印出1 0,有些人可能希望打印1 1。这与子shell的原理相同,其中$( )是具有继承环境的子shell。

答案 1 :(得分:0)

这是由管道造成的,请考虑这个最小的例子,其中k变量保持不变:

k=0
echo "nothing" | k=5
echo $k

这将打印0。所以,如果你想让这个例子工作,最简单的方法就是将临时结果存储到一个文件中(在循环中),然后在循环外读取它。