以公共的字段连接两个文件的行
命令语法格式
join [option]… file1 file2
命令描述
将每一对具有相同连接字段的输入行连接在一起并写入标准输出。它的行为与SQL语句的JOIN指令是类似的。在「使用示例」部分查看演示示例。
参数file1和file2可以是‘-’表示从标准输入中读取数据,但是不能同时为‘-’。file1和file2的连接字段需要先进行排序。
命令join的默认行为(未指定任何命令行参数时):
- 连接所使用的字段是每行中的第一个字段;
- 使用空白作为字段之间的分隔符,行上的前导空格会被忽略;
- 输出结果中的字段之间由空格进行分隔;
- 每个输出行都是由连接字段、file1中剩余的字段、file2中剩余的字段组成。
命令支持的选项及含义
-a file-number
除了正常打印外,还打印第file-number个文件中无法配对的行。file-number的取值只能为1和2中的一个。
默认情况下,join只会输出两个文件中能够配对的行,使用该选项可以将无法配对的行也打印出来。
–check-order
使用该选项后,如果用于连接的字段是未排序的,则产生错误。
–nocheck-order
不检查输入文件中用于连接的字段是否排序。这是默认行为。
-e string
用字符串替换输入中缺少的输出字段。即,缺少用-1, -2, -j, -o选项指定的字段。
–header
将每个输入文件的第一行视为标题行。标题行将被连接,并作为输出的第一行进行打印。如果使用了-o选项用于指定输出格式,则会根据指定的格式打印标题行。即使指定了–check-order,也不会检查标题行。
另外,如果文件中用于连接的字段的标题不匹配,则将使用第一个文件中的标题字段。
-i, –ignore-case
在连接比较时忽略大小写的差异。使用此选项,输入文件中用于连接的行也必须以忽略大小写的方式进行排序。可以使用’sort -f’来产生这种顺序。
-1 field
指定file1中用于连接的字段。field为正整数。
-2 field
指定file2中用于连接的字段。field为正整数。
-j field
等价于-1 field -2 field。
-o field-list, -o auto
如果指定了关键字’auto’,则从每个文件的第一行推断输出格式。这与默认输出格式相同,但也确保为每行输出相同数量的字段。缺少的字段被替换为-e选项指定的字符串,并且放弃额外的字段。
否则,按照field-list中的格式构建每个输出行。字段列表中的每个元素可以是单个字符’0’,也可以是m.n(其中m是文件编号’1’或’2’,n是字段的编号)。
字段规范’0’表示连接字段。在大多数情况下,可以使用对应于连接字段的显式m.n来实现’0’字段规范的功能。但是,当打印无法配对的行(使用-a或-v选项中的任何一个)时,如果两个文件中都有不可用的行,则无法使用字段列表中的m.n指定连接字段。为了加入该功能,POSIX发明了’0’字段规范表示法。
参数field-list中的元素用逗号或空白分隔。空白分隔符在Shell中通常需要引用。例如,命令join -o 1.2,2.2和join -o’1.2 2.2′是等价的。
所有输出行(包括因任何-a或-v选项而打印的输出行)都可以使用field-list进行指定。
-t char
使用字符char作为输入和输出字段分隔符。在输入文件中将每次出现的char视为重要字符。使用sort(1)的-t char选项,而不用sort的-b选项来产生这个顺序。如果指定join -t ,则将整行视为一个整体,匹配sort的默认操作。如果指定了-t ‘\0’,则使用ASCII NUL字符来分隔字段。
-v file-number
只打印第file-number个文件中无法配对的行。file-number的取值只能为1和2中的一个。
-z, –zero-terminated
使用零字节(ASCII NUL)而不是换行符(ASCII LF)分隔项目。即,将输入视为由ASCII NUL分隔的项目,并使用ASCII NUL作为终止字符输出项目。
此选项可与’perl -0’或’find -print0’和’xargs -0’结合使用,它们可以用于相同地处理任意文件名(甚至包含空格或其他特殊字符的文件名)。请注意使用-z选项时,换行符会被视为字段分隔符。
–help
显示帮助信息并退出。
–version
显示版本信息。
退出状态
退出状态为零表示成功,非零值表示失败。
关于排序
如果给出–check-order选项,未排序的输入将导致致命的错误消息。
如果给出选项–nocheck-order,则未排序的输入永远不会导致错误消息。
如果没有给出这些选项,则只有在发现输入文件包含不可配对的行并且两个输入文件都不为空时,才诊断产生错误排序的警告。如果输入文件被诊断为未排序,则join命令将以非零状态退出(并且不应使用输出)。
通过指定–nocheck-order强制join强制处理包含错误排序的输入文件,不能保证产生任何特定的输出。输出可能不符合你希望的结果。
使用示例
示例:演示命令join的功能
下面是一个简单的演示示例,解释了join的行为:
a 1
b 2
e 5
a X
e Y
f Z
a 1 X
e 5 Y
对要加入的文件进行排序:在连接之前先排序
命令join要求对输入文件进行排序。每个输入文件应根据连接中要使用的字段进行排序。推荐的排序命令是’sort -k 1b,1’(假设所需的连接字段为第一列)。
典型的用法如下:
# sort -k 1b,1 file2 > file2.sorted
# join file1.sorted file2.sorted > file3
上述的命令现将两个文件按照第一个字段进行排序,然后在通过第一个字段将文件连接起来。
通常,排序顺序是由LC_COLLATE语言环境指定的排序顺序。除非给出-t选项指定了分隔字符,否则命令join的排序比较会忽略用于连接的字段的开头的空格,如sort -b中所示。如果给出了–ignore-case选项,排序比较将忽略连接字段中的字符大小写,如sort -f中所示:
# sort -k 1bf,1 file2 > file2.sorted
# join –ignore-case file1.sorted file2.sorted > file3
如果将命令sort(1)的输出提供给命令join,则命令sort和命令join应使用一致的语言环境和选项。你可以使用类似’sort -k 1b,1’的命令对用于连接的字段进行排序,但是如果选择了非默认语言环境、连接字段、分隔符、比较选项等等,那么应该在sort和join中保持一致。
为避免出现与语言环境相关的任何问题,建议对两个命令使用“C”语言环境:
# LC_ALL=C sort -k 1b,1 file2 > file2.sorted
# LC_ALL=C join file1.sorted file2.sorted > file3
控制连接字段:连接不同的字段
使用-1,-2来设置每个输入文件的中用于连接的字段。但是要先确保用于连接的字段已经排序。
下面的示例使用第1个文件的第7个字段和第2个文件的第3个字段的值来连接两个文件:
# sort -k 3b,3 file2 > file2.sorted
# join -1 7 -2 3 file1.sorted file2.sorted > file3
如果两个文件的连接字段的编号相同,可以使用-j选项:
# sort -k4b,4 file2 > file2.sorted
# join -j4 file1.sorted file2.sorted > file3
如果对空白分隔的字段进行排序和连接操作,则需要指定不同的分隔符,使用-t选项:
# sort -t, -k3b,3 file2 > file2.sorted
# join -t, -j3 file1.sorted file2.sorted > file3
要指定一个制表符(ASCII 0x09)而不是空格,请使用:
# sort -t$’\t’ -k3b,3 file2 > file2.sorted
# join -t$’\t’ -j3 file1.sorted file2.sorted > file3
注意,$’\t’是由Shell支持的,如果Shell不支持则只能使用制表字符。
如果指定join -t”,则将认为整行与排序的默认操作匹配:
$ sort file2 > file2.sorted
$ join -t” file1.sorted file2.sorted > file3
配对和非配对行:控制连接的字段匹配
参考官方的手册来查看更多的示例,这些示例演示了如何控制输入字段。
标题行:使用文件中的标题行
当被连接的文件有一个未排序的标题行时,可以使用–header选项:
Name Age
Alice 25
Charlie 34
Name Country
Alice France
Bob Spain
Name Age Country
Alice 25 France
Bob NA Spain
Charlie 34 NA
注意,由于命令join命令要求用于连接的字段进行排序,所以需要用到sed -u进行排序。如下示例,对文件进行了排序并保留了第一行:
# ( sed -u 1q ; sort -k2b,2 ) < file2 > file2.sorted
# join –header -o auto -e NA -a1 -a2 file1.sorted file2.sorted > file3
上述命令中,命令sed读取了文件中的第一行,后续的内容被命令sort读取然后进行了排序。在sed命令中之所以使用了-u选项是因为缓冲的问题,需要进行下块的数据读取,不然sed会耗尽所有的数据,后面的命令sort就什么都读取不到了。参考「标准流中的缓冲」一文。
设置操作:文件的联合、交集、差异
结合sort,uniq,join来对文件执行一系列操作:
sort file1 file2 | uniq -d Intersection of unsorted files
sort file1 file1 file2 | uniq Difference of unsorted files
sort file1 file2 | uniq -u Symmetric Difference of unsorted files
join -t” -a1 -a2 file1 file2 Union of sorted files
join -t” file1 file2 Intersection of sorted files
join -t” -v2 file1 file2 Difference of sorted files
join -t” -v1 -v2 file1 file2 Symmetric Difference of sorted files
上面的所有示例都是以行为单位运行命令的,而不是在特定的字段上运行:没有-k选项以及使用join -t ”的排序都会将整行做为单位进行操作。
相关手册
comm(1), uniq(1), paste(1)
查看在线手册:http://www.gnu.org/software/coreutils/join
查看info手册:info ‘(coreutils) join invocation’
参考文献
- man 1 join, version GNU coreutils 8.28
- buffering in standard streams
更新日志
- 06/26/2018 创建文章
- 07/05/2018 修改文章内容,加入对示例中sed的-u选项的解释。