【第22期】观点:IT 行业加班,到底有没有价值?

与 '\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 编程中,如果变量的内容是纯粹的数据,就用引号括起来
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

1

“不愧是斗皇强者,虽然年龄比纳兰桀大上许多,可看他这股精神劲,若是没有意外的话,至少还能再活蹦乱跳的活个五十年,若是再来个好运,突破到斗宗强者,那恐怕就得步入那些老妖怪一般的级别了。”轻轻的将房门关上...

4

第五章 一封家书 暖洋洋的太阳照在伽罗的脸上,这是一个睡懒觉的好时间……但薇安儿的叫声,把伽罗从美梦中惊醒。“尼奥,你这个王八蛋!” 薇安儿如同被踩了尾巴的猫一样,扑向伽罗。“你为什么要划花莉莉娅的脸...
  • sarad
  • sarad
  • 2010-09-03 08:48
  • 34505

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

告诉你外语学习的真实方法及误区分析(精编版)-转

前 言  著名语言学家Greg Thomson说的:“外语学习的原理是如此之复杂,以至于没有人能说清楚;但掌握语言的过程又是如此之简单,以至于不需要说清楚。”讨论语言学习的原理,是件非常复杂的事,在下...
  • zery
  • zery
  • 2007-11-13 00:14
  • 25915

告诉你外语学习的真实方法及误区分析(精编版)

前 言   著名语言学家Greg Thomson说的:“外语学习的原理是如此之复杂,以至于没有人能说清楚;但掌握语言的过程又是如此之简单,以至于不需要说清楚。”讨论语言学习的原理,是件非常复杂的...

查找一个字符串中第一个只出现两次的字符

1、实现原理      哈希表是一种比较复杂的数据结构。由于比较复杂,STL中没有实现哈希表,因此需要我们自己实现一个。但由于本题的特殊性,我们只需要一个非常简单的哈希表就能满足要求。由于字符(cha...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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