linux命令tr小序

来源:互联网 发布:word2003软件官方下载 编辑:程序博客网 时间:2024/06/05 10:56

写在前面

linux下tr命令是个小巧的处理流的工具,它与其他处理流的最大不同是,它只能处理流中的单个字符。

tr应该是translate或者是transliterate(直译)的缩写。因此心中要牢牢记住tr的主要用途就是字符替换,注意是字符替换,而不是字符串替换。其次诸如删除,压缩功能可以看做是它的辅助功能,当然辅助功能也很重要,这些辅助功能大大增强了tr命令的灵活性。

还有一点很有意思,tr只处理来自标准输入的流,可见它主要用在管道命令中。

本文就tr的使用方法和使用注意事项做一些归纳总结,行文中也会穿插一些非常有用的使用案列,来加强学习。


语法格式

tr的命令格式很简单,如下

                      tr OPTION CHAR_SET1 [CHAR_SET2] 

我们先忽略tr的OPTION,着重看的是CHAR_SET1和CHAR_SET2。从命名上就能看出CHAR_SET1和CHAR_SET2是字符的集合。tr的主要功能就是把CHAR_SET1中的字符逐一替换成CHAR_SET2中对应位置的字符。来看两个例子吧:

(1)将“abc”替换成“xyz”

[15:05:43@astrol:~]# echo "abc" | tr "abc" "xyz"
xyz

我们要明白的是,tr "abc" "xyz"的意思是凡输入流中的字符a替换成x,字符b替换成字符y,字符c替换成z,而不是字符串abc替换成xyz。可以从以下的例子中看到结果:

[15:05:47@astrol:~]# echo "abcabc" | tr "abc" "xyz"
xyzxyz

(2)将小写字母替换成大写字母

[15:07:02@astrol:~]# echo "lowercase letters" | tr a-z  A-Z
LOWERCASE LETTERS

这个例子还可以写成:echo "lowercase letters" | tr [[:lower:]] [[:upper:]],效果是一样的。

好了,通过这两个例子我们可以掌握到:

(1)tr读取标准输入(stdin)的流,处理后默认输出到标准输出(stdout)

(2)tr接受两个字符集合参数,通过一一替换的工作方式处理输入流


指定CHAR_SET的方式

那么tr能允许我们通过什么方式来指定字符集呢? 说白了,就是tr能明白什么样形式的CHAR_SET。总结如下:

(1)普通字符

这个很容易理解,指定的字符代表的就是它们自身的含义。例如上面的那个将“abc”替换成“xyz”中每个字符代表的都是自身。

(2)对于那些不可打印字符,我们除了可以使用跟程序语言中的表现形式外,还可以通过指定ASCII的八进制形式来指定,例如制表符我们可以使用\t,也可以使用它的八进制形式\011,例如

[15:31:02@astrol:/tmp]# echo "a b c" | tr ' ' '\t'
a       b       c

同样的可以这样:

[15:31:47@astrol:/tmp]# echo "a b c" | tr ' ' '\011'
a       b       c

我们可以通过以下方式来验证是否真的起效了:

[15:31:52@astrol:/tmp]# echo "a b c" | tr ' ' '\011' | sed -n -e l
a\tb\tc$

的确,空格被替换成了制表符。这个功能在使用cut命令时会非常有用,因为cut的默认分隔符就是制表符。

同样的,这样的字符还有\\(反斜杠),\a(响铃声,这个很少用到),\b(退格键),\f(换页符),\n(换行),\r(回车),\v(垂直制表符)

(3)通过“M-N”的形式来指定字符范围。刚刚那个小写字母转换成大写字母的例子就是最典型的使用方式。

了解正则表达式或者SHELL通配符的童鞋,应该知道有个范围表达式,它是通过在方括号[ ]内指定字符范围的,但是tr不支持这个语法。这点一定要注意,否则有时会导致错误的发生。例如:

[10:34:43@astrol:/tmp]# echo "[123456789]" | tr -d '[0-9]'

你的本意可能只是想删除数字,但是tr会将方括号也一并删除!

此外,这种方式不具可移植性,因为排序是系统locale相关的。

(4)重复字符(Repeated characters)。

重复字符的形式有两种,分别为[CHAR*REPEAT][CHAR*]。

其中[CHAR*]的形式是针对CHAR_SET2的,CHAR_SET1不能指定这种形式。代表的意思是:重复指定的字符到与 CHAR_SET1 相同长度为止。

[10:55:52@astrol:/tmp]# echo "123456789" | tr '1-5' '[A*]'
AAAAA6789

[CHAR*REPEAT]代表的意思是将CHAR重复REPEAT次。例如

[12:18:34@astrol:/tmp]# echo "123456789" | tr '1-3' '[A*3]'
AAA456789

(5)使用POSIX字符类

这种方式最具移植性,可用的有:

[:alnum:] :所有字母字符与数字
[:alpha:] :所有字母字符
[:blank:] :所有水平空格
[:cntrl:] :所有控制字符
[:digit:] :所有数字
[:graph:] :所有可打印的字符(不包含空格符)
[:lower:] :所有小写字母
[:print:] :所有可打印的字符(包含空格符)
[:punct:] :所有标点字符
[:space:] :所有水平与垂直空格符
[:upper:] :所有大写字母
[:xdigit:] :所有 16 进位制的数字

举个例子:

[12:27:37@astrol:/tmp]# echo "lowercase letters" | tr  [:lower:]  A
AAAAAAAAA AAAAAAA


当CHAR_SET1和CHAR_SET2长度不相等

首先,我们在使用tr时绝大多数情况下CHAR_SET1和CHAR_SET2的长度是相等,这样才能体现一一替换的功能啊。

但是如果不相等,tr会怎么处理呢?

第一种情况:CHAR_SET1  < CHAR_SET2

这种情况下,tr的行为比较简单粗暴,直接丢弃CHAR_SET2中多余的字符即可。例如:

[12:35:16@astrol:/tmp]# echo "123456789" | tr 1-3 A-Z
ABC456789

很明显A-Z的长度大于1-3,tr直接舍弃了D-Z的字符,也可以理解成将CHAR_SET2的长度截短了,和CHAR_SET1长度相同。

第二种情况:CHAR_SET1 > CHAR_SET2

这种情况下,tr的默认行为是重复CHAR_SET2最后一个字符,直到长度与CHAR_SET1相同为止。还是看刚才的一个例子:

[12:41:01@astrol:/tmp]# echo "lowercase letters" | tr [:lower:]   A
AAAAAAAAA AAAAAAA

不过tr提供有一个选项-t,用来截断CHAR_SET1,使之长度等于CHAR_SET2。

[12:41:03@astrol:/tmp]# echo "lowercase letters" | tr -t [:lower:]  A
lowercAse letters

可以看到[:lower:]截短只剩字符a了,因此tr -t [:lower:]  A等同于tr a A。


tr的删除和压缩功能

tr提供-d选项用来删除在CHAR_SET1中的所有字符。例如:

[15:26:12@astrol:/tmp]# echo "123456789" | tr -d '19'
2345678

如果需要把windows下的文件转换成unix下的文件,除了可以使用dos2unix工具外,还可以tr -d '\r'即可。

tr提供-s选项用来压缩重复的字符,如果只提供了CHAR_SET1,则压缩CHAR_SET1中的所有字符;如果CHAR_SET1和CHAR_SET2都有,则压缩CHAR_SET2中的所有字符。例如:

[15:29:21@astrol:/tmp]# echo "aaaaabbbbb" | tr -s 'ab'
ab

用tr来删除文件中的空白行非常方便,使用tr -s '\n'即可。

再来一个例子:

[15:29:32@astrol:/tmp]# echo "aaaaabbbbb" | tr -s 'a' 'b'
b

是不是有些不解?其实这种情况下,tr先执行替换,结果就是bbbbbbbbbb,然后执行压缩,压缩字符b,因此最后的结果就是一个字符b了。这种组合在使用cut命令时非常有用,cut命令默认的分隔符是\t,而很多流中都是不定数量的空格,这时就可以使用 tr -s ' '  '\t'来现将空格替换成\t,然后压缩\t,就完美了。


另外,如果删除和压缩功能一起使用的话,tr先执行删除动作,然后执行压缩动作。例如:

[16:10:01@astrol:/tmp]# echo "aaabbbccc" | tr -d -s 'a' 'b'
bccc

先删除所有的字符a得到bbbccc,然后压缩字符b,得到最后的bccc。


最后,tr还有个-c选项,它的作用是取反CHAR_SET1,例如:

[17:06:58@astrol:/tmp]# echo "this is a test 12345" | tr -d -c '[:digit:]\n'
12345

这样就会删除除数字和换行符\n之外的所有字符了。


总结:

tr命令虽小,但是功能强大,花点时间学习还是很值得的!


参考链接:

《《tr命令-优化版》-linux命令五分钟系列之二十五》

0 0
原创粉丝点击