vieyahn2017 / shellv

shell command test and study
4 stars 1 forks source link

关于while read line 循环中变量作用域的问题 #93

Open vieyahn2017 opened 7 months ago

vieyahn2017 commented 7 months ago

https://www.cnblogs.com/Juststudy02/p/9842713.html

vieyahn2017 commented 7 months ago

前一阵用shell写了一个从数据库中抽取数据生成.xml文件的脚本,要求是每个文件中只生成1000条数据。于是用到了while read line 作为循环。

在制作文件计数器的时候发现了一个问题,在执行的过程中文件计数器(FILENUM)总是出现返回初始值的现象,具体简化的脚本如下:

#/bin/bash
FILENUM=1
for i in (多个表)
do
  #sql 语句 > .swap
  COUNTER=0
  cat .swap | while read line
  do
    #变量赋值以及写入文件的内容(不是重点,没细写)
    COUNTER=$[COUNTER+1]
    if [ $COUNTER -eq 1000 ]
    then
      #封包操作,封包的包名中附带了$FILENAME(没细写)
      FILENUM=$[FILENUM+1]
    fi
  done
  #封包操作,封包的包名中附带了$FILENAME,因为不能保证是1000条整数,所以read line跳出后还是需要执行这个操作。
  FILENUM=$[FILENUM+1]
done

基本流程如上:

在执行过程中发现文件计数器FILENUM总是有还原成默认值的情况。

经过调试发现,每一次while read line 循环的文件完成之后都会发生这种现象。

启动sh的时候同时也发现了两个同名的*.sh进程

经过查阅资料,发现在while read line 的用法中常用的有两种。

cat FILE | while read line
do
    `
done
while read line
do

done < FILE

经过分别测试得出以下结论:

使用管道符 | 的方法相当于启动了一个独立的子进程,因此循环中的变量FILENUM是属于自进程中的,与循环外的FILENUM虽然同名,但是值却不同。

使用重定向 < 的方法则不会有这种现象,在脚本启动时并没有子进程出现,因此循环内部变量FILENUM与循环外的FILENUM变量在同一个bash shell中。

vieyahn2017 commented 7 months ago
#!/bin/bash

tmpfile=/root/multipath_tmp
[ -e "$tmpfile" ] && rm -rf $tmpfile

this_inode=$(ifconfig Mgnt-0 | grep "inet " | awk '{print $2}')

function explain_one_foreach () {
    for lun in $(cat "$WWIDS" | grep -v ^# | sed s#/##g);
    do
        result=$(multipath -ll "$lun" 2> /dev/null)
        echo "$result" | grep " sd" | awk -v nlun="$lun" '{print nlun" "$3" "$2" "$5" "$6" "$7}' >> $tmpfile
    done
}

function explain_all () {
    results=$(multipath -ll 2> /dev/null)
    local lun=""
    local count=0
    echo "$results" | while read line;
    do
        if [ "${line:0:2}" == "36" ]; then
            lun=$(echo $line | awk '{print $1}')
            if [ ! -z "$last_lun" ] && [ "$count" -gt 0 ]; then
                echo "$last_lun at $this_inode count is [$count]"
            fi
            last_lun=$lun
            count=0
        fi
        if [ $(echo $line | grep -c " sd") -eq 1 ]; then
            echo "$line" | awk -v nlun="$lun" '{print nlun" "$3" "$2" "$5" "$6" "$7}'
            count=$((count+1))
        fi
    done
    echo "$lun at $this_inode count is [$count]"
}

WWIDS=/etc/multipath/wwids
if [ ! -f /etc/multipath/wwids ]; then
    echo "/etc/multipath/wwids files not existed"
    if [ $(multipath -ll  2>&1 | grep -c "DM multipath kernel driver not loaded") -eq 1 ]; then
        echo "DM multipath kernel driver not loaded"
        exit 1
    fi
fi

explain_all >> $tmpfile
exit 0

最后一行没有值 366c2222222222aa95116c76b00000163 sdc 33:0:0:2 active ready running 366c2222222222aa95116c76b00000163 sdg 34:0:0:2 active ready running 366c2222222222aa95116c76b00000163 sdk 35:0:0:2 active ready running 366c2222222222aa95116c76b00000163 sdo 36:0:0:2 active ready running 366c2222222222aa95116c76b00000163 at 2.2.2.2 count is [4] 366c2222222222aa95116c76b00000162 sdb 33:0:0:1 active ready running 366c2222222222aa95116c76b00000162 sdf 34:0:0:1 active ready running 366c2222222222aa95116c76b00000162 sdj 35:0:0:1 active ready running 366c2222222222aa95116c76b00000162 sdn 36:0:0:1 active ready running 366c2222222222aa95116c76b00000162 at 2.2.2.2 count is [4] 366c2222222222aa95116c76b00000165 sde 33:0:0:4 active ready running 366c2222222222aa95116c76b00000165 sdi 34:0:0:4 active ready running 366c2222222222aa95116c76b00000165 sdm 35:0:0:4 active ready running 366c2222222222aa95116c76b00000165 sdq 36:0:0:4 active ready running at 2.2.2.2 count is [0]

vieyahn2017 commented 7 months ago

#!/bin/bash

tmpfile=/root/multipath_tmp
rstfile=/root/multipath_rst
[ -e "$tmpfile" ] && rm -rf $tmpfile
[ -e "$rstfile" ] && rm -rf $rstfile

this_inode=$(ifconfig Mgnt-0 | grep "inet " | awk '{print $2}')

function explain_one_foreach () {
    for lun in $(cat "$WWIDS" | grep -v ^# | sed s#/##g);
    do
        result=$(multipath -ll "$lun" 2> /dev/null)
        echo "$result" | grep " sd" | awk -v nlun="$lun" '{print nlun" "$3" "$2" "$5" "$6" "$7}' >> $rstfile
    done
}

function explain_all () {
    multipath -ll > $tmpfile 2> /dev/null
    local lun=""
    local count=0
    while read line;
    do
        if [ "${line:0:2}" == "36" ]; then
            lun=$(echo $line | awk '{print $1}')
            if [ ! -z "$last_lun" ] && [ "$count" -gt 0 ]; then
                echo "$last_lun at $this_inode count is [$count]"
            fi
            last_lun=$lun
            count=0
        fi
        if [ $(echo $line | grep -c " sd") -eq 1 ]; then
            echo "$line" | awk -v nlun="$lun" '{print nlun" "$3" "$2" "$5" "$6" "$7}'
            count=$((count+1))
        fi
    done < $tmpfile
    echo "$lun at $this_inode count is [$count]"
}

WWIDS=/etc/multipath/wwids
if [ ! -f /etc/multipath/wwids ]; then
    echo "/etc/multipath/wwids files not existed"
    if [ $(multipath -ll  2>&1 | grep -c "DM multipath kernel driver not loaded") -eq 1 ]; then
        echo "DM multipath kernel driver not loaded"
        exit 1
    fi
fi

explain_all >> $rstfile
# cat $rstfile
exit 0

对了

366c2222222222aa95116c76b00000163 sdc 33:0:0:2 active ready running 366c2222222222aa95116c76b00000163 sdg 34:0:0:2 active ready running 366c2222222222aa95116c76b00000163 sdk 35:0:0:2 active ready running 366c2222222222aa95116c76b00000163 sdo 36:0:0:2 active ready running 366c2222222222aa95116c76b00000163 at 2.2.2.2 count is [4] 366c2222222222aa95116c76b00000162 sdb 33:0:0:1 active ready running 366c2222222222aa95116c76b00000162 sdf 34:0:0:1 active ready running 366c2222222222aa95116c76b00000162 sdj 35:0:0:1 active ready running 366c2222222222aa95116c76b00000162 sdn 36:0:0:1 active ready running 366c2222222222aa95116c76b00000162 at 2.2.2.2 count is [4] 366c2222222222aa95116c76b00000165 sde 33:0:0:4 active ready running 366c2222222222aa95116c76b00000165 sdi 34:0:0:4 active ready running 366c2222222222aa95116c76b00000165 sdm 35:0:0:4 active ready running 366c2222222222aa95116c76b00000165 sdq 36:0:0:4 active ready running 366c2222222222aa95116c76b00000165 at 2.2.2.2 count is [4]