您的位置:首页 > 运维架构 > Linux

Linux基础命令:文本处理工具之join , paste

2014-06-17 09:48 766 查看
大纲1、join 介绍2、join 语法格式3、join 实战演示4、paste 命令

版本信息
版本信息
join (GNU coreutils) 8.4
paste (GNU coreutils) 8.4

一、join 介绍

Linux下最常用的数据文件、配置文件的格式都是文本(ASCII)格式的(一切皆文本),使用分隔符来区分不同的字段,比如冒号(:)、制表符、空格等。像常见的/etc/passwd和
/etc/group两个文件就是用":"来分隔的。这种文本格式我们可以视为文本数据库,既方便人去阅读,也适合程序处理,通常某列类似于数据库中的关键字。
join命令就是一个根据关键字合并数据文件的命令(join lines of two files on a common
field),类似于关系型数据库中两张表关联查询。 如果了解关系型数据库的关联查询,那么join命令的工作原理很容易理解。
有过关系型数据库使用经验的同学都应该知道,当我们组合多个表进行查询时,通常要指定表之间如何关联的条件,否则会产生笛卡尔积。下例展示了如何通过 CategoryID字段联接
Categories和 Products表:
SELECT CategoryName, ProductName
FROM Categories INNER JOIN Products
ON Categories.CategoryID = Products.CategoryID;

二、join 语法格式

语法我们可以通过 join --help 命令查看:

Usage: join [OPTION]... FILE1 FILE2
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.

-a FILENUM        also print unpairable lines from file FILENUM, where
FILENUM is 1 or 2, corresponding to FILE1 or FILE2
-e EMPTY          replace missing input fields with EMPTY
-i, --ignore-case  ignore differences in case when comparing fields
-j FIELD          equivalent to '-1 FIELD -2 FIELD'
-o FORMAT         obey FORMAT while constructing output line
-t CHAR           use CHAR as input and output field separator
-v FILENUM        like -a FILENUM, but suppress joined output lines
-1 FIELD          join on this FIELD of file 1
-2 FIELD          join on this FIELD of file 2
帮助文档这样说到:
“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.”
join根据公共字段(关键字)来合并两个文件的数据行,然后送到标准输出。默认以空白(whitespace)分隔数据,并且默认比对第一个字段。
常用的有以下几个选项:
-t CHAR
指定分隔符,比如 -t':'则使用:作为分隔符,默认分隔符为空白[空格+TAB+换行](whitespace)。
-1 FIELD
指定第1个文件使用哪一个字段进行Join
-2 FIELD
指定第2个文件使用哪一个字段进行join
-a FILENUM
相当于OUTER JOIN

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

2.1 join与SQL关联类比:
内连接(inner join)                           ==   格式:join <FILE1> <FILE2>
左连接(left join, 左外连接, left outer join) == 格式:join -a1 <FILE1> <FILE2>
右连接(right join, 右外连接,right outer join)== 格式:join -a2 <FILE1> <FILE2>
全连接(full join, 全外连接, full outer join) == 格式:join -a1 -a2 <FILE1> <FILE2>


三、join 实战演示

Important: FILE1 and FILE2 must be sorted on the join fields.

需要注意的是:在使用join之前,文件最好使用sort进行排序处理。

准备测试数据:
# head month_en.txt month_zh.txt
==> month_en.txt <==
1   January
2   February
3   March
14  "Unknown"

==> month_zh.txt <==
1   一月
2   二月
3   三月
13  "十三月,故意的"
a、inner join
join 没有指定任何参数的情况下,默认使用whitespace作为分隔符,并使用第一个字段作为join关键字,忽略关键字不匹配的行。
# join month_en.txt  month_zh.txt
1 January 一月
2 February 二月
3 March 三月


b、左外连接(left outer join)
join -a1 month_en.txt  month_zh.txt
1 January 一月
2 February 二月
3 March 三月
14 "Unknown"
这次把"14 Unknown"这一行也显示出来了,也就是说把month_en.txt中不匹配的行也显示出来。

c、右外连接(right outer join)
# join -a2 month_en.txt  month_zh.txt
1 January 一月
2 February 二月
3 March 三月
13 "十三月,故意的"
这次显示”十三月,故意的”这一行显示出来,也就是把month_zh.txt不匹配的行显示出来。

d、全连接(full join)
# join -a1 -a2 month_en.txt  month_zh.txt
1 January 一月
2 February 二月
3 March 三月
13 "十三月,故意的"
14 "Unknown"
看到了吧,效果是很明显的。

e、指定分隔符
我们把/etc/passwd和/etc/shadow整合起来。
# head -n3 /etc/passwd /etc/shadow
[sudo] password for yy:
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

==> /etc/shadow <==
root:!:16212:0:99999:7:::
daemon:*:16177:0:99999:7:::
bin:*:16177:0:99999:7:::
我们看到,这两个文件都是以":"作为分隔符,我们以第一个字段作为join关键字
# join -t: /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash:!:16212:0:99999:7:::
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin:*:16177:0:99999:7:::
bin:x:2:2:bin:/bin:/usr/sbin/nologin:*:16177:0:99999:7:::
OK, 看到了吧,是不是非常方便。这里主要是用到SQL联合查询的概念。

四、paste

paste有什么作用呢?paste仅仅简单的把两个文件的行粘在一起,构成新行的字段【默认以TAB分隔】。它相比与join命令就简单得多了,join命令必须根据两个文件相关联的关键字,然后再进行合并,而paste什么都不考虑,直接进行合并。
paste 就是无条件的将两个文件对应的行组合起来。不用指定任何匹配条件。

# paste month_en.txt month_zh.txt
1   January     1   一月
2   February    2   二月
3   March       3   三月
14  "Unknown"   13  "十三月,故意的"
看出paste和join的差别了吗?当然,可以使用-d选项指定构成新行的分隔符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息