tr—字符串、文本转换工具
基础用法
tr主要用于字符串和文本内容的替换和删除,但不改变原字符串或文本。
语法:命令输出 | tr 选项 [SET1] [SET2] 或 tr 选项 [SET1] [SET2] < 处理文件
其中SET1为被替换或删除的字符集,SET2为要替换成的字符集,均支持正则表达式。
选项:
默认:替换(映射)所有
-c:反向替换(映射),即替换(映射)SET1的补集
-d:删除SET1
-s:去重SET1并替换(映射)为SET2
-t :截断SET1超出SET2长度的部分后再替换(映射)
命令详解:
1. 默认选项
[lsc@localhost ~]$ cat test.sh I love cats. I love rabbits. I love camels.
[lsc@localhost ~]$ tr cat dog < test.sh I love dogs. I love robbigs. I love domels.
发现tr并不是简单地将文本中的所有SET1替换为SET2,而是将SET1中的每一个字符替换为对应的SET2中的字符,此处即是将文本中所有的c替换为d,a替换为o,t替换为g,像一种一一映射的关系,但如果SET1的长度与SET2的长度不一致呢?
(1)SET1 > SET2 —— SET1多出来的字符映射为SET2最后一个字符
[lsc@localhost ~]$ tr cat do < test.sh I love doos. I love robbios. I love domels.
(2)SET1 < SET2 —— SET2多出来的字符无效
[lsc@localhost ~]$ tr ca dog < test.sh I love dots. I love robbits. I love domels.
(3)SET1中有重复字符 —— 以SET2最后一次映射的为准
[lsc@localhost ~]$ tr caa dog < test.sh I love dgts. I love rgbbits. I love dgmels.
常用用法——文本字符大小写替换:
例如将test.sh中的所有小写字符替换为大写字符:
[lsc@localhost ~]$ tr a-z A-Z < test.sh I LOVE CATS. I LOVE RABBITS. I LOVE CAMELS.
还可以用tr内置的变量[:lower:]和[:upper:](注意两者必须同时使用,否则会报错)
[lsc@localhost ~]$ tr [:lower:] [:upper:] < test.sh I LOVE CATS. I LOVE RABBITS. I LOVE CAMELS.
2. -c选项
[lsc@localhost ~]$ tr -c cat dog < test.sh gggggggcatgggggggggggagggtggggggggggcagggggg[lsc@localhost ~]$
-c选项的SET2只有最后一个字符是有效的,会将文本中除了SET1的所有字符替换为SET2的最后一个字符,这里包括文本最后的一个换行符,所以会发现Linux控制台前缀会出现在输出结果的后面,而不是另起一行。
再举一例:
[lsc@localhost ~]$ echo "abc" | tr -c a @ a@@@[lsc@localhost ~]$
这里使用-c反向替换echo输出的字符串后,Linux控制台前缀也会跟在命令输出结果的后面而非另起一行,而且明明原来字符串只有"abc"三个字符,替换后变成了四个字符,这也是因为echo命令总是会自带输出一个换行符到其右的字符串末尾,而字符串+换行符都会通过管道传给tr命令,所以这里tr命令真正处理的是管道传给它的"abc”三个字符加末尾一个换行符(这一点常常会被忽略,因为我们是用自己的视角看,而不是从tr命令的视角看)。
同理用默认正向替换尝试:
[lsc@localhost ~]$ echo "abc" | tr "\n" @ abc@[lsc@localhost ~]$
注意这里换行符\n可用双引号包裹,也可用单引号包裹:
[lsc@localhost ~]$ echo "abc" | tr ‘\n‘ @ abc@[lsc@localhost ~]$
或者再加一个反斜杠转义一下换行符自己的反斜杠:
[lsc@localhost ~]$ echo "abc" | tr \\n @ abc@[lsc@localhost ~]$
这里容易出错:Linux换行符\n,是两个字符缺一不可,但是Linux控制台上的反斜杠总是会自动与其后一个字符结合,自身消失变成一个新字符,所以必须加引号防止其拓展(单引号只需括反斜杠‘\‘,双引号要把"\n"全部括起来),或者在前面再加一个反斜杠先转义了换行符的反斜杠,使其在控制台上保留下来,再与n一起表示一个换行符。
3. -d选项
-d选项删除SET1,只需要SET1即可:
[lsc@localhost ~]$ echo "abc" | tr -d ab c
4. -s选项
-s选项可以不加SET2,只做去重操作,将文本中SET1重复的部分删除:
[lsc@localhost ~]$ echo "aabbbcccc" | tr -s abc abc
加上SET2,则先对SET1进行去重,再将去重后的SET1映射为SET2:
[lsc@localhost ~]$ echo "aabbbcccc" | tr -s abc 123 123
常用用法——去除文件中多余的空行、空格、制表符:
[lsc@localhost ~]$ cat test2.sh I love drumsticks. Drumsticks is delicious. Are you love Drumsticks? [lsc@localhost ~]$
[lsc@localhost ~]$ tr -s "\n\t " < test2.sh I love drumsticks. Drumsticks is delicious. Are you love Drumsticks? [lsc@localhost ~]$
发现-s选项在删除多余换行符的时候似乎达到了我们删除文件空行的效果(除了文本开头的空行,但它也不算多余的空行),简化一下这里的test2.sh文本(可以用echo -e输出到文件中试下):
"\nstr1\n\n\t\tstr2\n\n\n str3\n\n"
-s选项处理后的结果:
"\nstr1\n\tstr2\n str3\n"
这样就一目了然了,同时也解释了为什么不能使用-d选项删除文本中的空行(会使原来在两行的文本挤到同一行来)。
小拓展:对于特殊的字符可以使用Linux的ASCII码进行tr操作(man ascii命令查看):
换行符(\n)——012
制表符(\t)——011
空格符(SPACE)——040
上面举例的命令可以替换为:
tr -s "\012\011\040" < test2.sh
5. -t选项
-t选项会截断SET1超出SET2长度的部分然后再做正向映射:
[lsc@localhost ~]$ echo "abc" | tr -t ab @ @bc