tr主要用于映射结果集、压缩和删除字符。我个人感觉特别有用,特别是压缩连续空格(空行)为一个空格(空行),让不规则的信息变得规则。
2.5.1 tr映射
tr [options] [SET1] [SET2]
如果同时指定了SET1和SET2,则实现的是将SET1的符号按位置一一对应映射为SET2中的符号。实际上就是对应替换。
tr接收到stdin后首先会把标记意义上的符号替换为换行符,然后才执行指定的选项参数。什么是标记意义上的符号请看xargs的内容http://www.cnblogs.com/f-ck-need-u/p/5925923.html。
例如:
[root@xuexi tmp]# ls
a b c d logdir one one space.log shdir sh.txt space.log test vmware-root
[root@xuexi tmp]# ls | tr " " "\t" ç由于先替换为换行符,所以有且只有一个文本意义上的空格被替换为制表符
a
b
c
d
logdir
one
one space.log
shdir
sh.txt
space.log
test
vmware-root
如果在SET1中使用了\n,会发现最后的结果中是紧接着命令提示符。就像下面的。这就是因为原本最后一行的尾部是有分行符的,替换之后就没有了分行符。
[root@xuexi tmp]# echo {1..10} | tr "\n" "x"
1 2 3 4 5 6 7 8 9 10x[root@xuexi tmp]#
之所以说tr是映射而不是替换,是因为两个结果集替换的时候符号位置是一一对应的。例如下面例子的第二条命令,因为\n是SET1中的唯一一个也是第一个符号位,所以SET2中只取第一个符号位“X”进行替换。Y字符就被忽略了。
[root@xuexi tmp]# ls | tr "\n" "X"
aXbXcXdXlogdirXoneXone space.logXshdirXsh.txtXspace.logXtestXvmware-rootX
[root@xuexi tmp]# ls | tr "\n" "XY"
aXbXcXdXlogdirXoneXone space.logXshdirXsh.txtXspace.logXtestXvmware-rootX
那么这样就可以实现简单的加密和解密了。
[root@xuexi tmp]# echo "12345" | tr "0-9" "9876543210" ç加密
87654
[root@xuexi tmp]# echo "87654" | tr "0-9" "9876543210" ç解密
12345
上面的过程是将管道左边的12345对应到0-9的展开式0123456789,并将对应位映射到SET2的数字上。解密也是同理。
更典型的是ROT13加密算法,它的加密和解密使用一套字符。它的SET1的字母位和SET2的字母位完全反向成对。例如SET1指定符号是“axy”,如果SET2想将其对应为“opq”,则须将SET1扩展为“axyopq”,SET2扩展为“opqaxy”,最终是(a,x,y,o,p,q)和(o,p,q,a,x,y),这样(a,o)和(o,a)就配对了,无论加密还是解密都能使用这一套字符。将其扩展为A-Z和a-z就是ROT13加密,甚至还可以将0-9也加上去和9-0对应。下面是SET1和SET2的对应式。
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm
现在加密“I love you”
[root@xuexi tmp]# echo "I love you" | tr "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
V ybir lbh
将“V ybir lbh”解密。
[root@xuexi tmp]# echo "V ybir lbh" | tr "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
I love you
2.5.2 完全对应的替换
默认情况下,当指定的SET1比SET2字符长时,从最后一个对应的位置开始,SET1的剩余字符都和SET2的最后一个字符对应。假如SET1=[1234],SET2=[abc],则3对应c,4也对应c,此时如果tr的操作对象中出现3或者4都会被替换为c。
使用-t可以先截断SET1比SET2中长的字符,例如上面截断多余的4,SET1=[123]和SET2=[abc]就实现了完全对应。
[root@xuexi tmp]# cat x.txt
NO Name SubjectID Mark 备注
1 longshuai 001 56 不及格
2 gaoxiaofang 001 60 及格
3 zhangsan 001 50 不及格
4 lisi 001 80 及格
5 wangwu 001 90 及格
[root@xuexi tmp]# cat x.txt | tr "fang" "jin" ç结果中n和g都被替换为了n
NO Nime SubjectID Mirk 备注
1 lonnshuii 001 56 不及格
2 nioxiiojinn 001 60 及格
3 zhinnsin 001 50 不及格
4 lisi 001 80 及格
5 winnwu 001 90 及格
[root@xuexi tmp]# cat x.txt | tr -t "fang" "jin" çg被截断,只对应替换fan为jin
NO Nime SubjectID Mirk 备注
1 longshuii 001 56 不及格
2 gioxiiojing 001 60 及格
3 zhingsin 001 50 不及格
4 lisi 001 80 及格
5 wingwu 001 90 及格
2.5.3 压缩符号
这功能太爽了。
tr -s [SET1] [SET2]
它可以将指定的连续的SET1的第一个符号压缩并替换为SET2中的第一个,如果不指定SET2就仅仅只压缩。这样可以使结果变得具有固定的格式,传递给其他命令进行文本处理时就方便太多了。
假如x.txt文件中的内容如下,空格有的地方多,有的地方少,也就是说是一个没有格式的文件。
[root@xuexi tmp]# cat x.txt
NO Name SubjectID Mark 备注
1 longshuai 001 56 不及格
2 gaoxiaofang 001 60 及格
3 zhangsan 001 50 不及格
4 lisi 001 80 及格
5 wangwu 001 90 及格
使用tr压缩空格使其变的规则。
[root@xuexi tmp]# cat x.txt | tr -s “" "
NO Name SubjectID Mark 备注
1 longshuai 001 56 不及格
2 gaoxiaofang 001 60 及格
3 zhangsan 001 50 不及格
4 lisi 001 80 及格
5 wangwu 001 90 及格
如果指定SET2,假如替换为-。
[root@xuexi tmp]# cat x.txt | tr -s " " "-"
NO-Name-SubjectID-Mark-备注
1-longshuai-001-56-不及格
2-gaoxiaofang-001-60-及格
3-zhangsan-001-50-不及格
4-lisi-001-80-及格
5-wangwu-001-90-及格
如果指定的SET1或SET2超过1个字符,则两者都只取第一个字符。例如x.txt中的Mark列有两个连续的0,将其替换为a。
[root@xuexi tmp]# cat x.txt | tr -s “"00" "aa"
NO Name SubjectID Mark 备注
1 longshuai a1 56 不及格
2 gaoxiaofang a1 6a 及格
3 zhangsan a1 5a 不及格
4 lisi a1 8a 及格
5 wangwu a1 9a 及格
2.5.4 删除符号和补集
tr -d是删除指定的符号,只能接一个SET1。
[root@xuexi tmp]# cat x.txt | tr -d " "
NONameSubjectIDMark备注
1longshuai00156不及格
2gaoxiaofang00160及格
3zhangsan00150不及格
4lisi00180及格
5wangwu00190及格
tr -c SET1 SET2是求tr操作对象对SET1的补集,然后将补集字符全部替换为SET2。即将tr操作对象中不在SET1中存在的字符替换为SET2的字符。但是SET2如果指定的字符大于1个,则只取最后一个字符作为替换字符。使用-c的时候应该把-c SET1作为一个整体,不要将其分开。
例如:
[root@xuexi tmp]# echo "abcdefo"| tr -c "ao" "y"
ayyyyyoy[root@xuexi tmp]#
上面的是把“abcdefo”除ao的替换为y,即ayyyyyo,但是结果的最后面多了一个y并且紧接着命令提示符。这是因为abcdefo尾部的\n也是ao的补集的一部分,并将其替换为y了。如果不想替换最后的\n,可以在SET1中指定\n。
[root@xuexi tmp]# echo "abcdefo"| tr -c "ao\n" "y"
ayyyyyo
如果SET2指定多个字符,将只取最后一个字符作为替换字符。
[root@xuexi tmp]# echo "abcdefo"| tr -c "ao\n" "ay"
ayyyyyo
[root@xuexi tmp]# echo "abcdefo"| tr -c "ao\n" "yb"
abbbbbo
-c常和-d一起使用,tr -d -c SET1。它先执行-c SET1求出tr操作对象对SET1的补集,再对这个补集执行删除,也就是说最终的结果是SET1类的。注意,-d一定是放在-c前面的,否则执行的就不是删除补集,而是替换补集为-d的最后一个字符d了。
[root@xuexi tmp]# echo "one 1 two 2 three 3"| tr -d -c "[0-9]\n" ç对数字和分行符求补集,并删除这些补集符号
123
[root@xuexi tmp]# echo "one 1 two 2 three 3"| tr -d -c "[0-9] \n" ç多对一个空格求补集,这样结果中就保留空格了
1 2 3
[root@xuexi tmp]# echo "one 1 two 2 three 3"| tr -c "[0-9]\n" -d ç -d选项放在-c选项的后面是替换行为
dddd1ddddd2ddddddd3
[root@xuexi tmp]# echo "one 1 two 2 three 3"| tr -d -c "[a-zA-z]\n" ç保留字母
onetwothree
[root@xuexi tmp]# echo "one 1 two 2 three 3"| tr -d -c "[a-zA-z] \n" ç保留字母的同时保留空格
one two three
从上面补集的实验中可以看到,其实指定的[0-9]和[a-z]是一个类,最终的结果显示的是这个类中的对象。
在tr中可以使用以下几种类。这些类也可以用在其他某些命令中。
[:alnum:]所有的数字和字母
[:alpha:]所有的字母
[:blank:]所有水平空白=空格+tab
[:cntrl:]所有控制字符(非打印字符),在ascii表中的0-37对应的字符和127的del
[:digit:]所有数字
[:graph:]所有打印字符,不包含空格=数字+字母+标点
[:lower:]所有小写字母
[:print:]所有打印字符,包含空格=数字+字母+标点+空格
[:punct:]所有标点符号
[:space:]所有水平或垂直空白=空格+tab+分行符+垂直tab+分页符+回车键
[:upper:]所有大写字母
[:xdigit:]所有十六进制数字
使用方法例如下面的。例如[:upper:]等价于[A-Z],[:digit:]等价于[0-9]。
[root@xuexi tmp]# echo "one ONE 1 two TWO 2 three THREE 3" | tr -d -c "[:upper:] \n"
ONE TWO THREE
[root@xuexi tmp]# echo "one ONE 1 two TWO 2 three THREE 3" | tr -d -c "[:alpha:] \n"
one ONE two TWO three THREE
[root@xuexi tmp]# echo "one ONE 1 two TWO 2 three THREE 3" | tr -d -c "[:digit:] \n"
1 2 3