linux命令详解 join


原文链接: linux命令详解 join

最佳搭档:利用 sort 和 uniq 做集合运算 | 始终

linux 处理两个文件的并集,交集,差集

在求交集和差集的时候, 一定要注意, 养成先对文件sort和uniq的习惯。 另外, 求差集的方法非常巧妙, 需要仔细琢磨一下。
准备工作:先排序+去重
sort a.txt | uniq > old.txt
sort b.txt | uniq > new.txt

  1. 取出两个文件的并集(重复的行只保留一份)

cat old.txt new.txt | sort | uniq

  1. 取出两个文件的交集(只留下同时存在于两个文件中的文件)

cat old.txt new.txt | sort | uniq -d

  -d 输出duplicate了的行
  1. 删除交集,留下其他的行

cat old.txt new.txt | sort | uniq -u

  -u是unique的缩写, 表示输出唯一的行。
  1. 求差集 仅在 old.txt 中存在

cat old.txt new.txt new.txt | sort | uniq -u

sort命令

sort排序是根据从输入行抽取的一个或多个关键字进行比较来完成的。排序关键字定义了用来排序的最小的字符序列。缺省情况下以整行为关键字按ASCII字符顺序进行排序。

改变缺省设置的选项主要有:

  • m 若给定文件已排好序,合并文件
  • c 检查给定文件是否已排好序,如果它们没有都排好序,则打印一个出错信息,并以状态值1退出
  • u 对排序后认为相同的行只留其中一行
  • o 输出文件 将排序输出写到输出文件中而不是标准输出,如果输出文件是输入文件之一,sort先将该文件的内容写入一个临时文件,然后再排序和写输出结果。

改变缺省排序规则的选项主要有:

  • d 按字典顺序排序,比较时仅字母、数字、空格和制表符有意义。
  • f 将小写字母与大写字母同等对待。
  • I 忽略非打印字符。
  • M 作为月份比较:“JAN”<“FEB”
  • r 按逆序输出排序结果。
    -k, -key=POS1[,POS2] posl - pos2 指定一个或几个字段作为排序关键字,字段位置从posl开始,到pos2为止(包括posl,不包括pos2)。如不指定pos2,则关键字为从posl到行尾。字段和字符的位置从0开始。
  • b 在每行中寻找排序关键字时忽略前导的空白(空格和制表符)。
  • t separator 指定字符separator作为字段分隔符。

uniq命令

文件经过处理后在它的输出文件中可能会出现重复的行。例如,使用cat命令将两个文件合并后,再使用sort命令进行排序,就可能出现重复行。这时可以使用uniq命令将这些重复行从输出文件中删除,只留下每条记录的唯一样本。

说明:这个命令读取输入文件,并比较相邻的行。在正常情况下,第二个及以后更多个重复行将被删去,行比较是根据所用字符集的排序序列进行的。该命令加工后的结果写到输出文件中。输入文件和输出文件必须不同。如果输入文件用“- ”表示,则从标准输入读取。

该命令各选项含义如下:

  • c 显示输出中,在每行行首加上本行在文件中出现的次数。它可取代- u和- d选项。
  • d 只显示重复行。
  • u 只显示文件中不重复的各行。
  • n 前n个字段与每个字段前的空白一起被忽略。一个字段是一个非空格、非制表符的字符串,彼此由制表符和空格隔开(字段从0开始编号)。
    +n 前n个字符被忽略,之前的字符被跳过(字符从0开始编号)。
  • f n 与- n相同,这里n是字段数。
  • s n 与+n相同,这里n是字符数。

我使用过的Linux命令之join - 根据关键字合并数据文件

Linux下最常用的数据文件格式是文本格式的,多个字段之间通过分隔符来区分,分隔符比如冒号(:)、制表符、空格等。/etc/passwd和/etc/group就是用:来分隔的,用MySQL的into outfile指令导出的数据通常是以制表符分隔的。这种文本格式既方便人去阅读,也适合程序处理,通常某列类似于数据库中的关键字。join命令就是一个根据关键字合并数据文件的命令(join lines of two files on a common field),类似于数据库中两张表关联查询。
常用参数

join命令根据公共字段(关键字)来合并两个文件的数据行。因此最简单的使用方式就是指定两个数据文件名,这两个文件的第一列就是公共字段,字段之间以空白分隔。(For each pair of input lines with identical join fields, write a line to standard output. The default join field is the first, delimited by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.)

内连接(inner join) 格式:join
左连接(left join, 左外连接, left outer join) 格式:join -a1
右连接(right join, 右外连接,right outer join) 格式:join -a2
全连接(full join, 全外连接, full outer join) 格式:join -a1 -a2

指定分隔符:
-t
比如:-t ':' 使用冒号作为分隔符。默认的分隔符是空白。

指定输出字段:
-o ...
其中FILENO=1表示第一个文件,FILENO=2表示第二个文件,FIELDNO表示字段序号,从1开始编号。默认会全部输出,但关键字列只输出一次。
比如:-o 1.1 1.2 2.2 表示输出第一个文件的第一个字段、第二个字段,第二个文件的第二个字段。

使用示例
示例一 内连接(忽略不匹配的行)
不指定任何参数的情况下使用join命令,就相当于数据库中的内连接,关键字不匹配的行不会输出。

[root@rhel55 linux]# cat month_cn.txt
1 一月
2 二月
3 三月
4 四月
5 五月
6 六月
7 七月
8 八月
9 九月
10 十月
11 十一月
12 十二月
13 十三月,故意的
[root@rhel55 linux]# cat month_en.txt
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December
14 MonthUnknown

注:注意两个文件的内容,中文版的多了十三月,英文版的多了14月,这纯粹是为了方便演示。
[root@rhel55 linux]# join month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
[root@rhel55 linux]#
示例二 左连接(又称左外连接,显示左边所有记录)

显示左边文件中的所有记录,右边文件中没有匹配的显示空白。

[root@rhel55 linux]# join -a1 month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
13 十三月,故意的
[root@rhel55 linux]#

示例三 右连接(又称右外连接,显示右边所有记录)

显示右边文件中的所有记录,左边文件中没有匹配的显示空白。

[root@rhel55 linux]# join -a2 month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
14 MonthUnknown
[root@rhel55 linux]#

示例四 全连接(又称全外连接,显示左边和右边所有记录)

[root@rhel55 linux]# join -a1 -a2 month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
13 十三月,故意的
14 MonthUnknown
[root@rhel55 linux]#

示例五 指定输出字段

比如参数 -o 1.1 表示只输出第一个文件的第一个字段。

[root@rhel55 linux]# join -o 1.1 month_cn.txt month_en.txt
1
2
3
4
5
6
7
8
9
10
11
12
[root@rhel55 linux]# join -o 1.1 2.2 month_cn.txt month_en.txt
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December
[root@rhel55 linux]# join -o 1.1 2.2 1.2 month_cn.txt month_en.txt
1 January 一月
2 February 二月
3 March 三月
4 April 四月
5 May 五月
6 June 六月
7 July 七月
8 August 八月
9 September 九月
10 October 十月
11 November 十一月
12 December 十二月
[root@rhel55 linux]# join -o 1.1 2.2 1.2 1.3 month_cn.txt month_en.txt <== 字段1.3并不存在
1 January 一月
2 February 二月
3 March 三月
4 April 四月
5 May 五月
6 June 六月
7 July 七月
8 August 八月
9 September 九月
10 October 十月
11 November 十一月
12 December 十二月
[root@rhel55 linux]#

示例六 指定分隔符

[root@rhel55 linux]# join -t ':' /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash:$1$K8WSIAfQ$9i1h6a4V1XeIn0lv.CT53/:14833:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin::14833:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:
:14833:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin::14833:0:99999:7:::
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin:
:14833:0:99999:7:::
sync:x:5:0:sync:/sbin:/bin/sync::14833:0:99999:7:::
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown:
:14833:0:99999:7:::
halt:x:7:0:halt:/sbin:/sbin/halt::14833:0:99999:7:::
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin:
:14833:0:99999:7:::
news:x:9:13:news:/etc/news:::14833:0:99999:7:::
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin:
:14833:0:99999:7:::
operator:x:11:0:operator:/root:/sbin/nologin::14833:0:99999:7:::
games:x:12:100:games:/usr/games:/sbin/nologin:
:14833:0:99999:7:::
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin::14833:0:99999:7:::
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin:
:14833:0:99999:7:::
nobody:x:99:99:Nobody:/:/sbin/nologin:*:14833:0:99999:7:::
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin:!!:14833:0:99999:7:::
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin:!!:14833:0:99999:7:::
rpc:x:32:32:Portmapper RPC user:/:/sbin/nologin:!!:14833:0:99999:7:::
mailnull:x:47:47::/var/spool/mqueue:/sbin/nologin:!!:14833:0:99999:7:::
smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin:!!:14833:0:99999:7:::
pcap:x:77:77::/var/arpwatch:/sbin/nologin:!!:14833:0:99999:7:::
ntp:x:38:38::/etc/ntp:/sbin/nologin:!!:14833:0:99999:7:::
dbus:x:81:81:System message bus:/:/sbin/nologin:!!:14833:0:99999:7:::
avahi:x:70:70:Avahi daemon:/:/sbin/nologin:!!:14833:0:99999:7:::
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin:!!:14833:0:99999:7:::
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin:!!:14833:0:99999:7:::
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin:!!:14833:0:99999:7:::
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin:!!:14833:0:99999:7:::
avahi-autoipd:x:100:101:avahi-autoipd:/var/lib/avahi-autoipd:/sbin/nologin:!!:14833:0:99999:7:::
oprofile:x:16:16:Special user account to be used by OProfile:/home/oprofile:/sbin/nologin:!!:14833:0:99999:7:::
xfs:x:43:43:X Font Server:/etc/X11/fs:/sbin/nologin:!!:14833:0:99999:7:::
gdm:x:42:42::/var/gdm:/sbin/nologin:!!:14833:0:99999:7:::
sabayon:x:86:86:Sabayon user:/home/sabayon:/sbin/nologin:!!:14833:0:99999:7:::
oracle:x:500:500::/opt/oracle:/bin/bash:$1$v64Pa.m.$GZMrQiOWCdQPF8XKtWju30:14833:0:99999:7:::
mysql:x:101:104:MySQL server:/var/lib/mysql:/bin/bash:!!:14866::::::
[root@rhel55 linux]#
问题思考

  1. 怎样使用join命令实现两个文件中关键字的交集、并集、差集?

  2. 怎样使用join命令中指定关键字的列,而非默认的第一列?
    相关资料

【1】甜菜与咸菜 缺哪补哪,用技术武装自信 linux 的join命令--总结

【2】动态网站制作指南 深入浅出SQL之左连接、右连接和全连接

`