这篇文章向大家介绍如何基本文本处理的四个命令,分别是cut、paste、join和tr,这四个命令可以完成对文本的切割拼接以及文本内容的替换,在Shell编程中经常会用到,希望对你有帮助。
一、使用cut命令选取文本列
cut命令可以从垂直方向上对文本进行操作,下面介绍cut命令的使用方法。
1. cut命令及其语法
cut命令的基本语法如下:
cut option... [file]...
在上面的语法中,option表示选项,cut命令常用的选项如下所列:
- -b: 只选择指定的字节。
- -c: 只选择指定的字符。
- -d: 自定义列分隔符,默认值为制表符。
- -f: 只选择列表中指定的文本列,文本列用列号表示,多个列用逗号隔开。
- -n: 取消分隔多字节字符。
- -s: 不输出不包含列分隔符的行。
file参数表示要处理的的文本列表,多个文件名之间用空格分隔。
2.选择指定的文本列
这里以/etc/passwd文件为例,我们通过cut命令获取文件中的用户名和家目录:
下面是我截取passwd文件的一部分内容:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nolojiequgin
我们通过cut命令截取我们想要的内容:
[root@localhost ~]# cut -d ":" -f 1,6 /etc/passwd
root:/root
bin:/bin
daemon:/sbin
adm:/var/adm
lp:/var/spool/lpd
如果我们想要截取一段连续的列,可以这样:
[root@localhost ~]# cut -d ":" -f 1-3 /etc/passwd
root:x:0
bin:x:1
daemon:x:2
adm:x:3
lp:x:4
如果我们要获取第三列开始一直到行尾的列:
[root@localhost ~]# cut -d ":" -f 6- /etc/passwd
/root:/bin/bash
/bin:/sbin/nologin
/sbin:/sbin/nologin
/var/adm:/sbin/nologin
/var/spool/lpd:/sbin/nologin
我们也可以结合上面三种方式获取想要的内容:
[root@localhost ~]# cut -d ":" -f 1,2,4-5 /etc/passwd
root:x:0:root
bin:x:1:bin
daemon:x:2:daemon
adm:x:4:adm
lp:x:7:lp
3. 选择指定数量的字符
除了可以从文本中获取列外,用户还可以通过cut命令获取每一行中指定数量的字符。在选择字符时,cut命令的语法如下:
cut -c list
其中-c选项表示选择字符,list表示要选择的范围,可以是以下语法形式:
- 1-4,6 表示选择每行的1~4个字符和第六个字符。
- 3,5,8 表示选择第3,5,8个字符。
- -4,8 选择1~4的字符和第八个字符。
- 3- 选择从第三个字符开始一直到结尾。
举例:
[root@localhost ~]# cut -c 1-5 /etc/passwd
root:
bin:x
daemo
adm:x
lp:x:
注意:由于选择字符是将整行看作一个字符串进行处理的,所以不需要也不能指定列分隔符。
4. 排除不包含列分隔符的行
cut命令的-s参数可以帮助我们排除掉一些不包含正确列分隔符的行。
[root@random_wz ~]# cat demo.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
hello
[root@random_wz ~]# cut -s -d":" -f 1 demo.txt
root
bin
daemon
adm
lp
可以看到demo.txt其文件的最后一行hello没有包含冒号分隔符,因此并没有被输出。
注意:只要文本行中包含一个列分隔符,都会被包含-s选项的cut命令输出。
二、使用paste命令拼接文本列
1. paste命令及其语法
前面介绍了只用cut命令截取文本行内容,但是如果我们想要将多个文件的列拼接起来,那么就可以使用paste命令了。
paste命令的基本语法如下:
paste [option]... [file]...
其中paste命令常用的参数如下:
- -d:指定拼接结果中列的分隔符,默认是制表符。
- -s:将多个文件串行地拼接在一起,也就说将后面文件的内容添加到前面文件的末尾。
注意:paste命令并不要求参与拼接的文件中的文本行是有序的,另外,paste命令只是简单的进行文本行的拼接,并不进行任何关键字的比较。
2. 自定义列分隔符
我们通过-d参数指定两个文件的分隔符:
[root@random_wz ~]# cat demo1.txt
hello world
good morning
hello every
yesterday
[root@random_wz ~]# cat demo2.txt
mysql
python
c++
golang
shell
[root@random_wz ~]# paste -d "@" demo1.txt demo2.txt
hello world@mysql
good morning@python
hello every@c++
yesterday@golang
@shell
注意:paste命令只是简单的拼接文本行,如果用户想要根据关键字进行拼接,paste命令就不适用了,需要用到join命令。
三、使用join命令连接文本列
1. join命令及其语法
join命令可以根据两个文本中的公共列来连接数据行,其基本语法如下:
join [option]... file1 file2
在上面的语法中,option表示join命令的相关选项,常用的选项如下所列:
- -1 field:根据第一个文件的指定列进行连接,其中field用来指定第一个文件中用来连接的关键字列。
- -2 field:根据第二个文件的指定列进行连接,其中field用来指定第二个文件中用来连接的关键字列。
- -a filenum:指定是否输出不匹配的行。其中filenum可以取值为1或者2,分别代表第一个文件和第二个文件。
- -e string:使用参数string指定的字符串代替空列。
- -i :在比较关键字时忽略大小写。
- -o:自定义输出列。
- -t:自定义列分隔符。
- -v filenum:该选项的功能是输出filenum指定的文件的所有行。
先来看一下join命令最简单的用法:
[root@random_wz ~]# cat demo1.txt
03151143 wang
03151144 random_w4
03151145 random_w2
03151146 random_w1
03151147 random_w5
03151148 random_w7
[root@random_wz ~]# cat demo2.txt
03151143 陕西
03151144 广东
03151145 陕西
03151146
[root@random_wz ~]# join demo1.txt demo2.txt
03151143 wang 陕西
03151144 random_w4 广东
03151145 random_w2 陕西
03151146 random_w1
2. 指定联接关键字列
默认情况下,join命令会将两个文件的第一列作为关键字列进行比较,但是我们也可以通过-1参数和-2参数指定关键字列:
[root@random_wz ~]# cat demo1.txt
03151143 wang
03151144 random_w4
03151145 random_w2
03151146 random_w1
03151147 random_w5
03151148 random_w7
[root@random_wz ~]# cat scores.txt
1 03151143 80
2 03151144 82
3 03151145 89
4 03151146 88
5 03151147 82
[root@random_wz ~]# join -1 1 -2 2 demo1.txt scores.txt
03151143 wang 1 80
03151144 random_w4 2 82
03151145 random_w2 3 89
03151146 random_w1 4 88
03151147 random_w5 5 82
注意:在默认情况下,join命令在比较关键字时会区分大小写,但是用户可以使用 -i 选项来忽略大小写的区别。
3. 内联接文本文件
所谓内联接文本文件,实际上就是使用默认选项的join命令对两个文本文件的联接操作,默认join命令只输出匹配关键字的文本行,而忽略关键字不匹配的行,如下图:
注意:参与联接的两个文件必须按照关键字排序,否则会出现错误。但是用户可以通过指定–nocheck-order 选项来使join命令不检查文件是否按照关键字排序。
4. 左联接文本文件
所谓左联接文本文件是指在联接结果中输出左边文件的所有行,即使在右边的文件中没有匹配到的行。在左联接中,对于在右边的文件没有相应关键字的行,使用空白字符代替。如下图:
在join命令中,要实现左联接,语法如下:
join -a 1 file1 file2
下面举个例子:
[root@random_wz ~]# cat demo1.txt
03151143 wang
03151144 random_w4
03151145 random_w2
03151146 random_w1
03151147 random_w5
03151148 random_w7
[root@random_wz ~]# cat demo2.txt
03151143 陕西
03151144 广东
03151145 陕西
03151146
[root@random_wz ~]# join -a 1 demo1.txt demo2.txt
03151143 wang 陕西
03151144 random_w4 广东
03151145 random_w2 陕西
03151146 random_w1
03151147 random_w5
03151148 random_w7
5. 右联接文本文件
右联接恰好和左联接相反,它是将右边文件的所有行全部显示出来,而在不匹配的行中,左边文件的内容使用空白填充。如下图:
右联接的基本语法如下:
join -a 2 file1 file2
下面举个例子:
[root@random_wz ~]# cat demo1.txt
03151143 wang
03151144 random_w4
03151145 random_w2
03151146 random_w1
03151147 random_w5
03151148 random_w7
[root@random_wz ~]# cat demo2.txt
03151143 陕西
03151144 广东
03151145 陕西
03151146
[root@random_wz ~]# join -a 2 demo1.txt demo2.txt
03151143 wang 陕西
03151144 random_w4 广东
03151145 random_w2 陕西
03151146 random_w1
6. 全联接文本文件
所谓全联接文本文件,是指除了显示两个文件中关键字匹配成功的行以外,还包括前后两个文件中所有不匹配的行,不匹配的文件内容通过空白字符填充。如下图:
全联接的语法如下:
join -a 1 -a 2 file1 file2
下面举个例子:
[root@random_wz ~]# cat demo1.txt
03151143 wang
03151144 random_w4
03151145 random_w2
03151146 random_w1
03151147 random_w5
03151148 random_w7
[root@random_wz ~]# cat demo2.txt
03151143 陕西
03151144 广东
03151145 陕西
03151146
[root@random_wz ~]# join -a 1 -a 2 demo1.txt demo2.txt
03151143 wang 陕西
03151144 random_w4 广东
03151145 random_w2 陕西
03151146 random_w1
03151147 random_w5
03151148 random_w7
注意:在进行全联接时,选项-a 1 -a 2不能写在一个-a选项中,只能重复使用两个-a选项。
7. 自定义输出列
在默认情况下,join命令会输出参与链接的两个文件的所有列。但是在某些情况下,用户可能并不需要得到所有的列,就可以使用-o选项来指定输出的列的清单。-o 选项可以接受一个字段的列表,其语法如下:
join filenum.field file1 file2
filenum表示文件号,可以取值为1~2,field为文件中的列号,下面举个例子:
[root@random_wz ~]# cat demo1.txt
03151143 wang
03151144 random_w4
03151145 random_w2
03151146 random_w1
03151147 random_w5
03151148 random_w7
[root@random_wz ~]# cat scores.txt
1 03151143 80
2 03151144 82
3 03151145 89
4 03151146 88
5 03151147 82
[root@random_wz ~]# join -1 1 -2 2 -a 1 -o 1.1 1.2 2.3 demo1.txt scores.txt
03151143 wang 80
03151144 random_w4 82
03151145 random_w2 89
03151146 random_w1 88
03151147 random_w5 82
03151148 random_w7
四、 使用 tr 命令替换文件中的内容
1. tr命令和其基本语法
tr是单词 translate 的前面两个字母,其功能是转换或者删除指定的字符。与其它文本处理命令不同,tr命令不能直接从文本文件中读取数据,只能从标准输入获取数据,并且将处理结果写入标准输出设备。
tr命令的基本语法如下:
tr [option]... set1 [set2]
在上面的语法中,option表示 tr 命令的选项,常用的选项如下:
- -c:用字符集set2替换字符集set1中没有包含的字符。
- -d:删除字符集set1中的所有字符,不执行替换操作。
- -s:压缩set1中重复的字符。
- -t:将字符集set1用set2替换。
set1和set2分别表示参与操作的两个字符集,其中set1用于查询,set2用于处理各种转换操作。也就是说,凡是在字符集set1中出现的字符,将被替换成在set2中相应位置上的字符。
tr命令中的字符集使用类似于正则表达式的形式来表达,常用的语法格式如下:
- [a-z]:所有小写字母。
- [A-Z]:所有大写字母。
- [0-9]:单个数字。
- /octal:一个三位八进制数,对应有效的ASCII字符。
- [char*n]:表示char重复出现n次。
另外tr命令还支持字符类,这里参照博客
中的正则表达式的字符集。
2. 去除重复出现的字符
#! /usr/bin/env bash
# 压缩重复字符
result=`tr -s "[a-z]" < $1`
echo ${result}
Output:
[root@random_wz ~]# cat demo.txt
Hello everyoneeeeeee, my nammmmmmmme -a random_w .Nice toooo me you, I want to be your friends. Would you like?
[root@random_wz ~]# sh test.sh demo.txt
Helo everyone, my name -a random_w .Nice to me you, I want to be your friends. Would you like?
3. 删除空行
#! /usr/bin/env bash
# 删除空行
result=` cat demo.txt | tr -s ["\n"]`
echo "${result}"
Output:
[root@random_wz ~]# cat demo.txt
Hello everyone
Good Morning
Good evening
[root@random_wz ~]# sh test.sh
Hello everyone
Good Morning
Good evening
注意:换行符也可以用\012表示,\012为换行符的ASCII值。
4. 大小写转换
大小写转换的语法如下:
tr [a-z] [A-Z]
使用上面的命令会将标准输入的字符中所有的小写字母转换为大写字母,反之亦然。
#! /usr/bin/env bash
# 大小写转换
result=` cat demo.txt | tr [a-z] [A-Z]`
echo "${result}"
Output:
[root@random_wz ~]# cat demo.txt
Hello World!
[root@random_wz ~]# sh test.sh
HELLO WORLD!
5. 删除指定的字符
使用tr命令的 -d 参数可以快速的删除文本中出现的某些字符。
#! /usr/bin/env bash
# 删除数字和冒号
result=` cat demo.txt | tr -d "[0-9][:]"`
echo "${result}"
Output:
[root@random_wz ~]# cat demo.txt
Tuesday 09:10
Wednesday 09:20
Thursday 10:09
Friday 11:20
Saturday 12:10
Sunday 10:00
[root@random_wz ~]# sh test.sh
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
注意:在使用tr命令时,注意字符集表示一个个单独的字符,而非字符串。因此tr -d “[Hello]” 表示的是文本中出现的5个字符,而非Hello这个字符串。
除了上面的方法外,我们还可以通过补集的方式进行字符的删除:
#! /usr/bin/env bash
# 删除数字和冒号
result=` cat demo.txt | tr -cs "[a-z][A-Z]" "[\n*]"`
echo "${result}"
Output:
[root@random_wz ~]# cat demo.txt
Tuesday 09:10
Wednesday 09:20
Thursday 10:09
Friday 11:20
Saturday 12:10
Sunday 10:00
[root@random_wz ~]# sh test.sh
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday