您现在的位置是:亿华云 > 系统运维
Shell逐行处理文本求和,我人傻了...
亿华云2025-10-08 21:05:04【系统运维】8人已围观
简介本文转载自微信公众号「编程珠玑」,作者守望先生 。转载本文请联系编程珠玑公众号。假设要要计算文本test.data的第二列的数字之和:112223334456 当然你可能会这样处理:aw
本文转载自微信公众号「编程珠玑」,行处作者守望先生 。理文转载本文请联系编程珠玑公众号。本求
假设要要计算文本test.data的和人第二列的数字之和:
1 12 2 23 3 34 4 56当然你可能会这样处理:
awk { s+=$2} END { print s} test.data很快就得到了结果。不过,行处本文要说的理文点与awk无关。我们通过另外一种方式来计算,本求即逐行分析处理的和人方式。
尝试一
我们尝试第一种方式,行处shell实现如下:
#!/usr/bin/env bash sum=0 cat test.data | while read line do temp_num=$(echo "$line" | cut -d -f 2) sum=$(( $sum + $temp_num )) done echo "we get sum:$sum"输出结果:
we get sum:0这是理文为什么!为什么得到的结果会是0呢?
这事坏就坏在脚本中的|,众所周知,本求这是和人一个管道命令,而这也就意味着,行处while循环的理文执行结果都是在一个subshell中,一旦这个subsell退出了,本求它里面的结果也就没有了。
其实这个问题利用有了这个神器,高防服务器再也不怕shell写得不对了中提到的工具很容易发现:
$ shellcheck myscript Line 3: cat test.data | while read line ^-- SC2002: Useless cat. Consider cmd < file | .. or cmd file | .. instead. ^-- SC2162: read without -r will mangle backslashes. Line 6: sum=$(( $sum + $temp_num )) ^-- SC2030: Modification of sum is local (to subshell caused by pipeline). ^-- SC2004: $/${ } is unnecessary on arithmetic variables. ^-- SC2004: $/${ } is unnecessary on arithmetic variables. Line 8: echo "we get sum:$sum" ^-- SC2031: sum was modified in a subshell. That change might be lost. $尝试二
既然管道命令不建议用,那么我们使用下面的方式看看:
#!/usr/bin/env bash sum=0 for line in $(cat test.data) do echo "get line :$line" temp_num=$(echo "$line" | cut -d -f 2) sum=$(( $sum + $temp_num )) done echo "we get sum:$sum"输出结果:
get line :1 get line :12 get line :2 get line :23 get line :3 get line :34 get line :4 get line :56 we get sum:135从结果中看出,如果文本中存在空格或者tab等,则看似每次读取一行,实际上是遇到空格,tab或换行就停止读取了,并没有达到我们的目的。
我们预期的应该是遇到换行才停止读取,为了达到这个目的,我们可以设置这个标记,即通过设置IFS来达到目的。在上面的shell开头加上:
IFS=$\n但是修改为这样之后,在自己的系统上并没有得到我想要的效果,有知道的读者可以告知一下。
尝试三
让我们再换一种方式:
#!/usr/bin/env bash sum=0 while read line do echo "line $line" temp_num=$(echo "$line" | cut -d -f 2) sum=$(( $sum + $temp_num )) done < "test.data" echo "we get sum:$sum"这种方式我们是网站模板能得到正确结果的。
当然,如果你要读取指定列,你还可以像下面这样做:
#!/usr/bin/env bash sum=0 while read col1 col2 do sum=$(( $sum + $col2 )) done < "test.data" echo "we get sum:$sum"其中col1,col2就分别代表了第一列,第二列,使用的时候,可以直接使用对应列的内容。
但是,如果我们要读取的内容包括了转义字符会怎么办?例如:
\n 12 \n 23 \n 34 \n 56执行结果:
line 12 line 23 line 34 line 56 we get sum:125从结果可以看到,虽然内容能否读取到,但是内容被打印出来的时候,已经变了,\被当成转义字符处理了,如果不想让它转义处理怎么办?只需要加上-r参数即可:
while read -r line总结
在逐行处理文本过程中,主要关注以下几种情况:
行中有空格,tab 行中有转义字符另外,通过shellcheck工具也会发现,它并不推荐for in file这种方式逐行处理文本:
Line 3: for line in $(cat test.data) ^-- SC2013: To read lines rather than words, pipe/redirect to a while read loop.作者:守望,linux应用开发者,目前在公众号【编程珠玑】,b2b供应网分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源
原文链接:https://mp.weixin.qq.com/s/rW0Va8g0U3apxNwR0Ziw9w
很赞哦!(8846)
上一篇: ④注册门槛低
下一篇: 第五步:重复第四步,直到找到正确的纪录。
相关文章
- 3.dns修改成功后,点击“域名解析”,按提示进行操作。解析格式一般如下:
- 十个JavaScript 开发者需要学习掌握的技巧
- Window下不用安装虚拟机,也可以玩转Linux,玩转最新Redis
- TypeScript 你还只会用 Any?
- cm域名有什么独特之处?新人要了解cm域名哪些?
- 两个小工具,MySQL死锁分析,新技能又Get!
- 记一次生产环境卡顿优化过程:大事务并发回滚
- Redis内存淘汰策略,看这一篇就够了!
- 众所周知,com域名拥有最大的流通市场和流通历史。最好选择com域名,特别是在购买域名时处理域名。其次可以是cn域名、net域名、org域名等主流域名,现在比较流行的王域名和顶级域名,都是值得注册和投资的。
- 七步操作!教你正确更换MySQL数据库字符集