shell脚本变量在循环中有值,出了循环就为空的bug问题解决

      最近遇到一个问题,在循环之前定义了一个变量,循环中会给该变量赋值,可是出了循环后该变量就变成空串了。在java中是不会出现这种情况的,百思不得其解,最后终于解决了,所以很有必要记下来,避免以后出现同样的问题。

      基本需求是读取文件中的内容,并对内容进行处理,然后按照一定的顺序拼接后重新输出到另一个文件。

      脚本如下:

#!/bin/bash

#源文件
sourceTxt=./source.txt
#转换文件
tranTxt=./tran.txt
#输出文件
distTxt=./dist.txt

rm -f $distTxt

#为了便于处理,先将制表符替换为|
cat ${sourceTxt}|sed 's/\t/\|/g'>${tranTxt}

distName=""
echo "${distName}"
cat ${tranTxt}|while read line
do
	echo "开始读取:${line}"
	#获取目标表名,并将其中的${COD}替换为00
	distName=`echo $line|awk -F'|' '{print $1}'|sed 's/\${COD}/00/g'`
	#获取目标表字段名
	distCol=`echo $line|awk -F'|' '{print $2}'`
	#获取目标表字段属性
	distLen=`echo $line|awk -F'|' '{print $3}'`
	#获取目标表主键标识
	distPri=`echo $line|awk -F'|' '{print $4}'`
	
	#拼接并输出 将|再转换为制表符,便于数据放到Excel
	echo "${distName}|${distCol}|${distLen}|${distPri}"|sed 's/|/\t/g'>>${distTxt}
	echo "==============="
done 

#在输出文件最后添加一行 此时distName的值为空串
echo "${distName}|Timestamp|datetime|${distPri}"|sed 's/|/\t/g'>>${distTxt}

按常理讲,shell中的变量默认为全局变量,但输出结果中显示新添加的行中目标表名为空串:

经过排查发现问题出在while循环的写法上。while读取文件时一般有两种写法,通过管道符或者通过重定向。这里我用的管道符。主要区别在于重定向是内建命令,而管道符不是内建命令。linux执行shell时,会创建“子shell”进程运行shell中的命令,当运行到非内建指令时,会创建“孙shell”进程运行非内建指令。为了验证,可以在while循环中增加sleep 10,然后查看10秒内的进程树,如下,即此时while循环是在“孙进程”中运行的:

将while的写法换成重定向方式,如下:

while read line
do
	echo "开始读取:${line}"
	#获取目标表名,并将其中的${COD}替换为00
	distName=`echo $line|awk -F'|' '{print $1}'|sed 's/\${COD}/00/g'`
	#获取目标表字段名
	distCol=`echo $line|awk -F'|' '{print $2}'`
	#获取目标表字段属性
	distLen=`echo $line|awk -F'|' '{print $3}'`
	#获取目标表主键标识
	distPri=`echo $line|awk -F'|' '{print $4}'`
	
	#拼接并输出 将|再转换为制表符,便于数据放到Excel
	echo "${distName}|${distCol}|${distLen}|${distPri}"|sed 's/|/\t/g'>>${distTxt}
	sleep 10
	echo "==============="
done <${tranTxt}

此时的进程树显示while循环在子进程中运行,跟shell文件运行所在的进程一致,如下所示: 

查看运行结果,新添加的行中目标表名正常输出,如下:

你可能感兴趣的:(linux,shell,linux)