我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Linux shell逐行处理文本求和,我人傻了...

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Linux shell逐行处理文本求和,我人傻了...

 假设要要计算文本test.data的第二列的数字之和: 

  1. 1 12   
  2. 2 23   
  3. 3 34   
  4. 4 56  

当然你可能会这样处理: 

  1. awk '{s+=$2} END {print s}' test.data  

很快就得到了结果。不过,本文要说的点与awk无关。我们通过另外一种方式来计算,即逐行分析处理的方式。

尝试一

我们尝试第一种方式,shell实现如下: 

  1. #!/usr/bin/env bash  
  2. sum=0  
  3. cat test.data | while read line  
  4. do  
  5.     temp_num=$(echo "$line" | cut -d ' ' -f 2)  
  6.     sum=$(( $sum + $temp_num ))  
  7. done  
  8. echo "we get sum:$sum" 

输出结果:

  1. we get sum:0 

这是为什么!为什么得到的结果会是0呢?

这事坏就坏在脚本中的|,众所周知,这是一个管道命令,而这也就意味着,while循环的执行结果都是在一个subshell中,一旦这个subsell退出了,它里面的结果也就没有了。

其实这个问题利用有了这个神器,再也不怕shell写得不对了中提到的工具很容易发现: 

  1. $ shellcheck myscript  
  2. Line 3: 
  3. cat test.data | while read line  
  4.     ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.  
  5.                       ^-- SC2162: read without -r will mangle backslashes.  
  6. Line 6:  
  7.     sum=$(( $sum + $temp_num ))  
  8.     ^-- SC2030: Modification of sum is local (to subshell caused by pipeline).  
  9.             ^-- SC2004: $/${} is unnecessary on arithmetic variables.  
  10.                    ^-- SC2004: $/${} is unnecessary on arithmetic variables.  
  11. Line 8:  
  12. echo "we get sum:$sum"  
  13.                  ^-- SC2031: sum was modified in a subshell. That change might be lost.  

尝试二

既然管道命令不建议用,那么我们使用下面的方式看看: 

  1. #!/usr/bin/env bash  
  2. sum=0  
  3. for line in $(cat test.data) 
  4. do  
  5.     echo "get line :$line"  
  6.     temp_num=$(echo "$line" | cut -d ' ' -f 2) 
  7.     sum=$(( $sum + $temp_num ))  
  8. done  
  9. echo "we get sum:$sum" 

输出结果: 

  1. get line :1  
  2. get line :12  
  3. get line :2  
  4. get line :23  
  5. get line :3  
  6. get line :34  
  7. get line :4  
  8. get line :56  
  9. we get sum:135 

从结果中看出,如果文本中存在空格或者tab等,则看似每次读取一行,实际上是遇到空格,tab或换行就停止读取了,并没有达到我们的目的。

我们预期的应该是遇到换行才停止读取,为了达到这个目的,我们可以设置这个标记,即通过设置IFS来达到目的。在上面的shell开头加上: 

  1. IFS=$'\n' 

但是修改为这样之后,在自己的系统上并没有得到我想要的效果,有知道的读者可以告知一下。

尝试三

让我们再换一种方式: 

  1. #!/usr/bin/env bash  
  2. sum=0  
  3. while read line  
  4. do  
  5.     echo "line $line"  
  6.     temp_num=$(echo "$line" | cut -d ' ' -f 2)  
  7.     sum=$(( $sum + $temp_num ))  
  8. done < "test.data"  
  9. echo "we get sum:$sum" 

这种方式我们是能得到正确结果的。

当然,如果你要读取指定列,你还可以像下面这样做: 

  1. #!/usr/bin/env bash  
  2. sum=0  
  3. while read col1 col2  
  4. do  
  5.     sum=$(( $sum + $col2 ))  
  6. done < "test.data"  
  7. echo "we get sum:$sum" 

其中col1,col2就分别代表了第一列,第二列,使用的时候,可以直接使用对应列的内容。

但是,如果我们要读取的内容包括了转义字符会怎么办?例如: 

  1. \n 12  
  2. \n 23  
  3. \n 34  
  4. \n 56 

执行结果: 

  1. line   
  2.  12  
  3. line   
  4.  23  
  5. line   
  6.  34  
  7. line   
  8.  56  
  9. we get sum:125 

从结果可以看到,虽然内容能否读取到,但是内容被打印出来的时候,已经变了,\被当成转义字符处理了,如果不想让它转义处理怎么办?只需要加上-r参数即可: 

  1. while read -r line 

总结

在逐行处理文本过程中,主要关注以下几种情况:

  •  行中有空格,tab
  •  行中有转义字符

另外,通过shellcheck工具也会发现,它并不推荐for in file这种方式逐行处理文本: 

  1. Line 3:  
  2. for line in $(cat test.data)  
  3.             ^-- SC2013: To read lines rather than words, pipe/redirect to a 'while read' loop.  

 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Linux shell逐行处理文本求和,我人傻了...

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Linux shell逐行处理文本求和,我人傻了...

本文要说的点与awk无关。我们通过另外一种方式来计算,即逐行分析处理的方式。

Shell逐行处理文本求和,我人傻了...

为什么会这样呢?实际上,我们在《如何使用fork创建进程》中就提到过,fork的时候会拷贝父进程的数据内容,即写时复制,但是,像启动运行的线程,是不会被“复制”过去的。

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录