返回首页 两个月精通 Shell 脚本

shell 学习第十六天----join 练习

join 练习

两文件如下:t1.txt(tab 隔开每一列)

学号 姓名
001 xiaoming
002 zhangsan
t2.txt

科目号 学号 分数
0001   001 90
0002   001 80
0001   002 90
0002   002 100

合并为:
0001 001 xiaoming 90
0002 001 xiaoming 80
0001 002 zhangsan 90
0002 002 lisi     100

做法是:join -2 2 t1.txt t2.txt(但是不明觉厉)

join 的案例

例如有文件 aa 和 bb

aa 的内容为:
joe             100
jane            200
herman         300
chris           400
bb 的内容为:
joe             20
jane            10
syx             90
chris            98

如果使用命令 join aa bb,则输出结果为:

我们默认合并两个文件,它们将以行开头相同的内容为对照,如果一样,则抵消,把不同的合并为同一行。

chris 400 98
jane 200 10
joe 100 20

如果使用命令 join -a1 aa bb,则输出结果为:

chris 400 98
herman 300
jane 200 10
joe 100 20

使用 -a1 选项的意义是: 以第一个文件为主要内容合并,显示第一个文件的所有内容,不显示第二个文件不匹配规则的内容,(匹配规则为:行头一样,则允许合并,每行后续不同内容合并一起,相同的抵消)

如果使用命令 join -a2 aa bb,则输出结果为

chris 400 98
jane 200 10
joe 100 20
syx 90

使用 -a2 选项的意义: 以第二个文件为主要内容合并,显示第二个文件的所有内容,不显示第一个文件不匹配规则的内容,(匹配规则为:行头一样,则允许合并,每行后续不同内容合并一起,相同的抵消)

如果使用 join -a1 -a2 aa bb

chris 400 98
herman 300
jane 200 10
joe 100 20
syx 90

使用 -a1 -a2 选项的意义是: 合并两个文件的所有内容,但不符合规则的,则各自为一行。

如果使用命令 join -o 1.1 2.2,输出结果为:

chris 98
jane 10
joe 20

使用该选项的意义是: 使用自定义合并队列选项,1.1 代表第一个文件的第一列,2.2 代表第二个文件的第二列

如果输入命令 join -t ’ ’ -o 1.1 2.2 aa bb,输出结果为:

chris   98
jane    10
joe     20

使用该选项的意义是:使用分隔符,将会更加精确的定位合并内容。

最后针对一下 join 各个选项的意义给出一定的解释:

语法

join [-i][-a<1 或 2>][-e< 字符串 >][-o< 格式 >][-t< 字符 >][-v<1 或 2>][-1< 栏位 >][-2< 栏位 >][--help][--version][文件 1][文件 2]

补充说明:找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备。

参数

  • -a<1 或 2> 除了显示原来的输出内容之外,还显示指令文件中没有相同栏位的行。
  • -e< 字符串 > 若 [文件 1] 与 [文件 2] 中找不到指定的栏位,则在输出中填入选项中的字符串。
  • -i 或 --igore-case 比较栏位内容时,忽略大小写的差异。
  • -o< 格式 > 按照指定的格式来显示结果。
  • -t< 字符 > 使用栏位的分隔字符。
  • -v<1 或 2> 跟 -a 相同,但是只显示文件中没有相同栏位的行。
  • -1< 栏位 > 连接 [文件 1] 指定的栏位。
  • -2< 栏位 > 连接 [文件 2] 指定的栏位。
  • --help 显示帮助。
  • --version 显示版本信息。

有没有发现一个问题,就是只能按照我写的来,稍微换换命令的参数就会出现说文件没有进行排序的提示?

需要注意的是,使用 join 连接两个文件的相关字段,都需要先进行排序。如果连接的主字段有重复,则会导致两个文件相关行的排列组合,请确保这是你需要的结果。

另外如果你想使用 -e 选项,需要使用 -o 选项来格式化列,否则 -e 是没有效果的。还有一点就是你会发现使用 -e -o 进行全连接的话,两个文件的关键列都必须使用上,负责 -e 会把缺失的关键列那也填补上相应的字符,有时候这并非我们期望的,具体的请自己行试验测试。

个人认为这是 join 命令的一点瑕疵,他应该两个文件如果全连接或者左连接右连接出现单独的关键键都应该是关键键名称而不是 -e 补充。不过这个瑕疵可以用 awk 来弥补一下,倒是挺容易。

join 命令,对文件格式的要求非常强,如果想要更灵活的使用,可用 AWK 命令,参加 AWK 实例。

join 标准输入

有时我们需要将多个格式相同的文件 join 到一起,而 join 接受的是两个文件的指令,此时我们可以使用管道和字符 “-",来实现 join file1 file2 | join - file3 | join - file4 这样就可以将四个文件 连接到 一起了。

大体介绍了一下 join,然后介绍一下和 join 非常类似的一个命令:paste

  • paste 将几个文件的相应行用制表符连接起来,并输出到标准输出。
  • paste [选项] file1 file2
  • -d 指定不同于空格或 tab 键的域分隔符。例如用#分隔域, 使用 -d#
  • -s 将每个文件合并成行而不是按行粘

代码示例:

[root@jbxue ~]# cat names 
Tony 
Emanuel 
Lucy 
Ralph 
Fred
[root@jbxue ~]# cat numbers 
(307) 555-5356 
(212) 555-3456 
(212) 555-9959 
(212) 555-7741 
(212) 555-0040

将两个文件合并,中间用 tab 键分隔开

代码示例:

paste names numbers
Tony      (307) 555-5356 
Emanuel   (212) 555-3456 
Lucy      (212) 555-9959 
Ralph    (212) 555-7741 
Fred     (212) 555-0040
cat addresses 
55-23 Vine Street,Miami 
39 University Place,New York 
17 E. 25th Street,New York 
38 Chauncey St.,Bensonhurst 
17 E. 25th Street,New York

将 三个文件合并

代码示例:

paste names addresses numbers
Tony    55-23 Vine Street,Miami        (307) 555-5356 
Emanuel         39 University Place,New York   (212) 
555-3456 
Lucy    17 E. 25th Street,New York     (212) 555-9959 
Ralph   38 Chauncey St.,Bensonhurst    (212) 555-7741 
Fred    17 E. 25th Street,New York     (212) 555-0040

感觉 paste 没什么难度。

paste 练习

文件 aa 的内容为:

123
aaa

文件 bb 的内容为:

456
bbb
bbb

使用命令 paste -s aa bb,输出结果为

123 aaa
456 bbb bbb

使用 paste -d ”#” aa bb,输出结果为:

123#456
aaa#bbb
#bbb

详解:

paste 是 linux 命令

用途:

从一个或多个文件中连接行。

语法:

paste [-s] [-d List] File1 ...

描述:

paste 命令从在命令行上指定的文件中读取输入。如果出现 -(减号)作为文件名,此命令从标准输入中读取。此命令连接给定的文件中的行并把结果行写到标准输出中。

缺省情况下,paste 命令把每个文件当作栏,并用制表符水平连接它们(并行合并)。可以把 paste 命令看作为 cat 命令(垂直连接,也就是一个接一个)的相对命令。

使用 -s 标志,paste 命令合并同一输入文件的后继行(串行合并)。缺省情况下,这些行用制表符连接。

下列特殊字符也可用在 List 参数中:

  • \n 换行符
  • \t 制表符
  • \\ 反斜杠
  • \0 空字符串(不是空字符)