shell变量中的回车符处理

  |   0 评论   |   4,724 浏览

由于在 shell 中经常处理文本文件.但是不同的平台文件的换行是多种多样的.比如 windows 的\r\n;
Linux 环境的\n;
在不同环境下读取的文件有可能会不一致.因此需要对字符串进行预处理;

实践

数据准备

先使用echo-e参数把表意字符转换为内码,存储到变量 a;然后对变量 a 进行打印验证;

[macbook@cc-2 ~]$a=`echo -e "hello\r\nworld\r\nthe third line\r\n"`
[macbook@cc-2 ~]$echo "$a"
hello
world
the third line
[macbook@cc-2 ~]$echo "$a" | od -c
0000000    h   e   l   l   o  \r  \n   w   o   r   l   d  \r  \n   t   h
0000020    e       t   h   i   r   d       l   i   n   e  \r  \n
0000036
[macbook@cc-2 ~]$

使用 tr

删除\r时使用如下代码:

echo "$a" | tr -d '\r'
echo "$a" | tr -d '\r' | od -c # 验证字符串中是否还有'\r'

使用 sed

通过管道把变量值传给 sed,使用sed进行变量值替换:

# 直接使用`\x0d`代表`\r`的转义字符,这个在 Centos 中可以完成转换
# 但是 MacOs 不能 working;
## versoin-1
echo "$a" | sed 's/\x0d//g' 
echo "$a" | sed 's/\x0d//g'  | od -c
## version-2
echo "$a" | sed 's/\r//g' 
echo "$a" | sed 's/\r//g'  | od -c

在 MacOs 中可以使用\r的可以显示的^M字符来表示;这个字符可以使用输入Ctrl+V再按Ctrl+M打出来.我的电脑是 Mac,可以直接使用键盘上的Ctrl来完成输入;

## Centos 与 Mac 都可以
echo "$a" | sed 's/^M//g' | od -c

下面再介绍一个更通用的方法:

# method 1
echo "$a" | sed $'s/\r//g' | od -c
# method 2
echo "${a//^M/}" | od -c

使用 ${var//origin/replacement} ( 推荐使用,效率最高 )

使用${var//a/b}最大的好处是不用使用管道,也就不会fork 出新的进程.十分有利于提交程序的效率;

代码如下:

[macbook@cc-2 ~]$echo "${a//$'\r'/}" | od -c
0000000    h   e   l   l   o  \n   w   o   r   l   d  \n   t   h   e
0000020    t   h   i   r   d       l   i   n   e  \n
0000033

注意上面的语法中的\r是用$'\r'包裹起来的.直接写${a//\r/}是行不通的.

杂记

tr 有一个参数叫 -d ,使用此参数可以直接删除字符内部的特定子串;
比如删除 he,可以使用如下代码进行试验,发现-d参数里面的值是字符集合,即不是子串;

[macbook@cc-2 ~]$echo "$a" | tr -d 'he'
llo
world
t tird lin

sed 十六进制 Mac 无法替换原因

对于sed 无法直接使用十六进制进行替换的原因:hex-codes-in-sed-not-behaving-as-expected-on-osx

There is no general concept of what "the OS and its functions understand" -- each program, function, etc understands its own particular set of metacharacters, escapes, etc. And it just happens thatseddoesn't do hex codes. But bash does (if you ask it to), so you can have it translate them before callingsedwith$'':

解释一下的意思是:在操作系统与函数层面,没有所谓的能不能理解或者是识别特定字符,每一个程序与函数都理解他自己特定的元字符逃逸字符.对于Centos平台可以,而Macos不可以是因为sed原本就不会处理十六进制数据,之所以CentOs可以,是因为CentOSBASH在对输入进行了预处理;

echo A | sed $'s/\x41/B/'

参考:

  1. hex-string-replacement-using-sed

评论

发表评论


取消