Silentdoer

导航

记录一次shell里局部变量的问题

一:起因是这样的,自己今天面试被问到怎么读取某文件夹下所有的文件的每一行的数值的总和;其中文件中数值在每一行里的格式为num|,如33|,因此我第一想到的是通过cut -d\| f1 file来获取每个文件的以|为分割的第一列的值,

相当于最终能够将某文件的数据变成 33 44 55这样的形式;当时只答出用find/cut来实现,但没有电脑无法做进一步的测试;面试回来后就自己实现了这个问题,最终正确的脚本是:

a=0;for file in $(find ./ -name "*");do [ -f $file ] &&for arg in $(cut -d\| -f1 $file);do ((a=$a+$arg));done;done;echo $a

这里遇到了一个很有趣的情况,就是当我对&&for....done;done的for...done加上()后a会变成第二个for内部的局部变量;因为一开始我怕&&后面不能完整执行一个for语句因此加了括号;

后面打印$a发现每次进入第二个for $a的初始值都是0;后来以为是a的作用域的原因又通过export a;也没用;

最后报着侥幸的心态把()删了就正确得到了自己想要的结果;

结论:单()内部的变量会是局部变量而不会用外部变量,网上查到的是()内的语句实际上是开启了一个子shell来执行,因此里面的变量不会用到当前shell(bash)的变量,而()内声明的变量也不会被()所获得;

 

这里找到了更好的做法,用awk替代cut方法是:(注意$NF表示最后一列,而$(NF-1)表示倒数第二列

awk -F ' ' '{print $2}' bbb.txt | awk '{sum+=$1}END{print sum}'

表示先以空格作为分隔符得到第二列(全是数值假设),然后再次awk这个$1就表示整行的意思,然后这个命令以END作为分割,前面是要先执行的操作,后面是执行完后的接下的操作;

如果该列不是数值则结果为0

而如果想拼接字符串则将上面的sum+=$1改为sum=sum$1就是一个拼接操作;

posted on 2018-04-10 18:27  Silentdoer  阅读(626)  评论(0编辑  收藏  举报