与 '\r' 字符的两次交锋

原创 2016年06月01日 00:51:35

背景

众所周知,不同的操作系统中,对文本中换行的表示是不同的,在 windows 中用 \r\n 表示,在 Linux 中用 \n 表示,而在 Mac OS 中用 \r 表示。对于像笔者这种以 Windows 作为开发环境,Linux 作为执行环境的程序员来说,经常会不可避免地碰到由换行符不一致而引起到奇怪问题,下面就回溯一下我曾遇到并解决的两个相关的问题,希望能给读者来一点启发。

奇怪的脚本

这是同事遇到的问题,其当时在开发一个 shell 脚本,需要一个从文件中查找关键字的功能,比如文件名叫 data.txt,要查找到关键字是 warn,很容易写出这样的命令:

grep warn data.txt

假如文件的内容是:

warn: wrong
info: good
warn: not good

那么该命令因该返回两行:

warn: wrong
warn: not good

到这里,一切都正常,但是这位同事不满足于只将结果打印到标准输出,而是要用一个变量存储,以便后续的操作,于是写下了这样两行脚本:

result=$(grep warn data.txt)
echo $result

这时奇怪的事发生了,执行这个脚本得到的结果是:

_warn: not good  # 注意 'warn' 前面有一个空格,为了醒目,用 '_' 表示

相信读者已经猜到,导致这个现象的原因,就是 \r 字符。下面解释一下原因。
这个文件的出处现已无从考证,但其中每行都是以 \r\n 结束, 推测应该是从 Windows 平台拷贝过来的。但是在 Linux 中,只有 \n 被作为换行符,其前面的 \r 字符将被视为普通的文本内容处理,所以 grep 命令返回到结果应该为:

warn: wrong\r
warn: not good\r

在向屏幕打印这段内容时,\r 字符会被转义为回车符,其作用是将光标即下一个字符的输出位置移动到本行行首(Windows 上的 \r\n 可以理解为先将输出位置移动到行首,再用 \n 移动到下一行),但由于 \r 后面再无其它字符,所以对用户来说,仅光标位置的移动是感知不到的。
但在脚本中,情况有了些许的变化—— grep 的结果不直接打印,而是先赋值给变量,再打印变量。区别在于脚本中会将 result 中的内容按行分割,再依次传给 echo ,实际执行的命令为:

echo warn: wrong\r warn: not good\r

上面已经说过,\r 字符会使光标回到行首,所以第一个 \r 字符前的内容会被后面的内容覆盖,这便是问题所在。
其实只要将输出命令写成:

echo "$result"

而不是

echo $result

就不会有这个问题,因为双引号中的内容会被当作纯粹的字符串处理,不做转义,实际的命令为:

echo "warn: wrong\r
warn: not good\r"

内容分为两行打印,和直接用 grep 输出的结果一样。

链不到的库

这次到问题出现在另一同事的脚本中,其内容只有两行编译命令,被打在一个 rar 包中发给我。两行命令的内容都查不多,但命令的内容无关紧要,假设为:

g++ -Wall source.cpp -I...-L... -o source -lxxx

其中的 xxx 是一个本项目的动态库。我直接在本地执行该脚本,但链接失败,报 ‘xxx’ 库找不到。
第一反应当然是库所在的目录没有被加到动态库的搜索路径中,但检查了一遍发现不是。又怀疑命令写的有问题、动态库文件没有读权限、文件名写错,但都验证通过了。折磨了有半个小时,突然灵光一现,用 dos2unix 命令转换了一下编译脚本,随即编译通过。
原因很简单,这个脚本中每一行的末尾都有一个 \r,恰好跟在 ‘xxx’ 后面,变成了 ‘xxx\r’,链接时实际查找的是 ‘xxx\r’ 文件,当然找不到了。但由于打印到屏幕上的内容是一样到,所以很难发现。

经验教训

  • 如果环境不能一致,起码尽量做到配置和工具一致,许多 Windows 上到编辑器都支持将默认换行符都配置为 \n,Linux 上也有 zip、gzip 等压缩工具
  • 不可轻信外来的代码和数据,要做校验
  • shell 编程中,如果变量的内容是纯粹的数据,就用引号括起来
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

统计第一个只出现两次的字符

方法一:在一个一维数组里面查询: 最直接的方法是从头到尾遍历这个字符数组的字符,当访问这个字符时,拿这个字符和后面的每个字符匹配,如果下次又找到一个字符再次出现,就表明是出现两次的字符,如果字符与...

“二马”交锋下一站:线下伙伴和大数据

游戏、电商、O2O、社交、移动支付……阿里巴巴和腾讯前所未有的产业PK丝毫没有停止的迹象,无论是业务创新还是投资并购,两家巨头互不相让。曾经“电商霸主”和“社交寡头”的定位再也无法体现两家公司日趋模糊...

沉痛记下这次与 mysql 的交锋,以全面溃败结束

最近在做一个博客系统,后台使用 ssh 框架,前台使用 bootstrap ,因为不是太熟悉,所以遇到不少问题,但看到成果一步步做出来,喜悦之情溢于言表! 然而今天,遇到了一个让我崩溃的问题,战斗了...

深夜交锋:华为中兴回击美报告

一场深夜的交锋:华为中兴回击美负面报告 http://www.21cbh.com/2012/firstdaily_109/453318.html   这是一场开始于去年的交锋,持续到北京时间昨天深...

黑客们很喜欢骇客交锋,虽然本片不被影评人认可

黑客们很喜欢骇客交锋,虽然本片不被影评人认可。   虽然本片不被影评人认可,黑客们却很喜欢骇客交锋。可是,当谷歌 Chrome团队的主管 Parisa Tabriz组建了200 多名平静专家旁观了首...

HDU2548 两军交锋【数学计算+水题】

两军交锋 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub...

quart-z 两次执行问题

  • 2015-10-10 16:49
  • 20KB
  • 下载

我的两次破解经历(心情贴,无技术内容)

因为一直没有钻研,所以很久没有写这种技术性的文章了。这两天颇有收获,如果不记录下来恐怕日后遗忘。按理说应该写到我的CSDN博客上,但是那里已经荒废很久了,而空间又很久没有更新了,所以还是两边都发布一下...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)