join 是 paste 的一个很好的增强版本。join 只有在所要连接的文件共享某个共同的域时才会工作。
举例来说,考虑我们上面介绍 paste 时所使用的两个文件。下面是在使用 join 对其进行合并时所发生的事情:
注意这并没有显示任何东西。join 工具必须要在所操作的文件之间找到共同的域,默认情况下,它期望这个共同的域就是第一个域。
要了解这是如何工作的,我们可以尝试添加一些新内容。假设 fileone 现在包含以下内容:
aaaa Jurassic Park
bbbb AI
cccc The Ring
dddd The Mummy
eeee Titanic
|
filetwo 现在包含以下内容:
aaaa Neil 1111
bbbb Steven 2222
cccc Naomi 3333
dddd Brendan 4444
eeee Kate 5555
|
现在,再次尝试下面的命令:
# join fileone filetwo
aaaa Jurassic Park Neil 1111
bbbb AI Steven 2222
cccc The Ring Naomi 3333
dddd The Mummy Brendan 4444
eeee Titanic Kate 5555
|
此时第一个域相同的地方就会被识别出来,匹配项也就进行了合并。paste 是盲目地从每个文件中提取内容并创建输出结果;而 join 则是只合并那些匹配的行,这种匹配必须非常精确。举例来说,假设您向 filetwo 文件中添加一行内容:
aaaa Neil 1111
bbbb Steven 2222
ffff Elisha 6666
cccc Naomi 3333
dddd Brendan 4444
eeee Kate 5555
|
现在这个命令只会产生下面的输出结果了:
# join fileone filetwo
aaaa Jurassic Park Neil 1111
bbbb AI Steven 2222
|
只要这两个文件不再匹配了,就不会再执行任何操作了。第一个文件的每一行都匹配且只匹配于第二个文件相同行的默认域。如果找到匹配项,它们就会组成输出;否则就不再执行任何操作了。
默认情况下,join 只会查找第一个域进行匹配,并输出所有列的内容;不过我们可以对这种行为进行修改。-1 选项让我们可以指定使用哪个域作为 fileone 中的匹配项, -2 选项让我们可以指定使用哪个域作为 filetwo 中的匹配项。
举例来说,要对 fileone 的第二个域和 filetwo 的第三个域进行匹配,我们可以使用下面的语法:
# join -1 2 -2 3 fileone filetwo
|
-o 选项可以以 {file.field} 格式来指定输出结果。因此,要在匹配行上打印 fileone 的第二个域和 filetwo 的第三个域,语法为:
# join -o 1.2 -o 2.3 fileone filetwo
|
在实践中可以使用 join 工具最明显的方法是从 /etc/passwd 中提取用户名和对应的主目录项,并从 /etc/group 文件中提取组名。组名在 /etc/passwd 文件中是以数字的格式出现在第四个域中的。类似地,它们在 /etc/group 文件中是在第三个域中出现的。
# join -1 4 -2 3 -o 1.1 -o 2.1 -o 1.6 -t":" /etc/passwd /etc/group
root:root:/root
bin:bin:/bin
daemon:daemon:/sbin
adm:adm:/var/adm
lp:lp:/var/spool/lpd
nobody:nobody:/
vcsa:vcsa:/dev
rpm:rpm:/var/lib/rpm
nscd:nscd:/
ident:ident:/home/ident
netdump:netdump:/var/crash
sshd:sshd:/var/empty/sshd
rpc:rpc:/
|
awk 是 Linux 上功能最为强大的工具之一。它本身实际上是一种编程语言,可以实现复杂的逻辑语句,还可以简化部分文本的提取。在本文那中我们将不会详细对其进行介绍,而是快速了解一下它的语法,并尝试几个实际的例子。
awk 命令包括一个模式和由一条或多条语句构成的操作,语法如下所示:
awk '/pattern/ {action}' file
|
请注意:
- awk 测试指定文件中的每个记录是否符合模式匹配。如果找到匹配项,就执行指定的操作。
- awk 可以在管道中作为过滤器,如果没有指定文件,它也可以从键盘(标准输入)中接收输入。
一种非常有用的操作是打印数据!下面是如何引用一条记录中的域。
$0 —— 整条记录
$1 —— 该记录中的第一个域
$2 —— 该记录中的第二个域
我们还可以从一条记录中提取多个域,之间使用逗号分开。
举例来说,要提取 /etc/passwd 文件中的第 6 个域,命令如下:
# awk -F: '{print $6}' /etc/passwd
/root
/bin
/sbin
/var/adm
/var/spool/lpd
/sbin
/sbin
/sbin
/var/spool/mail
/etc/news
/var/spool/uucp
|
注意 -F 是由预先定义的 FS 变量所定义的输入域分隔符。在我们这个例子中是空格。
要从 /etc/passwd 文件中提取第一个和第六个域,命令如下:
# awk -F: '{print $1,$6}' /etc/passwd
root /root
bin /bin
daemon /sbin
adm /var/adm
lp /var/spool/lpd
sync /sbin
shutdown /sbin
halt /sbin
mail /var/spool/mail
news /etc/news
uucp /var/spool/uucp
operator /root
|
要在域之间使用短横线代替冒号来打印这个文件的内容,命令如下:
# awk -F: '{OFS="-"}{print $1,$6}' /etc/passwd
root-/root
bin-/bin
daemon-/sbin
adm-/var/adm
lp-/var/spool/lpd
sync-/sbin
shutdown-/sbin
halt-/sbin
mail-/var/spool/mail
news-/etc/news
uucp-/var/spool/uucp
operator-/root
|
要使用短横线作为域之间的分隔符来打印文件,并且只以逆序打印第一个域和第六个域,命令如下:
# awk -F: '{OFS="-"}{print $6,$1}' /etc/passwd
/root-root
/bin-bin
/sbin-daemon
/var/adm-adm
/var/spool/lpd-lp
/sbin-sync
/sbin-shutdown
/sbin-halt
/var/spool/mail-mail
/etc/news-news
/var/spool/uucp-uucp
/root-operator
|
head 工具打印每个文件的最开始部分的内容(默认是 10 行)。如果没有给定文件,它就从标准输入中读入内容,如果给定了文件名就从文件中读入内容。
举例来说,如果我们希望从 memo 文件中提取前两行内容,命令如下:
# head -2 memo
In order to better serve the needs of our mass
market customers, ABC Publishing is
integrating the groups selling to this channel
for ABC General Reference and ABC Computer
Publishing. This change will allow us to
better coordinate our selling and marketing
efforts, as well as simplify ABC's
relationships with these customers in the
areas of customer service, co-op management,
and credit and collection. Two national
account managers, Ricky Ponting and Greeme
Smith, have joined the sales team as a result
of these changes.
|
我们可以使用 -c 选项指定要显示的字节个数。举例来说,如果我们希望从 memo 文件中读取前两个字节的内容,可以使用下面的命令:
tail 工具打印每个文件的最末尾部分的内容(默认是 10 行)。如果没有给定文件,它就从标准输入中读入内容,如果给定了文件名就从文件中读入内容。
举例来说,如果我们希望从 memo 文件中提取最后两行内容,命令如下:
# tail -2 memo
Please join me in welcoming each of our new team members.
|
我们可以使用 -c 选项指定要显示的字节个数。举例来说,如果我们希望从 memo 文件中读取最后五个字节的内容,可以使用下面的命令:
现在我们已经知道如何使用各种工具从标准 Linux 文件中向外提取数据了。一旦提取出数据之后,这些数据就可以进行查看、打印或重定向到其他文件或数据库中了。了解了如何使用这些有用的工具可以帮助我们减少花费在烦杂任务上的时间,从而能够成为一名效率更高的管理员。
|