<笔记> Linux BASH 常用管线命令总结

在 BASH 的管线操作中,有很多实用的小工具可以帮我们快速处理文本数据,这些工具可以帮我们完成数据选取、排序、转换、分割等常见操作,极大提升文本处理的效率。下面我们就来逐一梳理这些常用命令的用法。

一、选取命令:cut、grep

选取命令的作用是将一段数据经过分析后,取出我们想要的部分,这类命令通常是针对一行一行的信息来进行分析的。

cut

cut 可以将一行信息的某一段切出来,处理的信息以行为单位,非常适合处理有固定格式的文本。

语法格式:

  • cut \-d\&\#39;分隔字符\&\#39; \-f fields:用于有特定分隔字符的场景

  • cut \-c 字符区间:用于排列整齐的信息

参数说明

  • \-d:后面接分隔字符,与 \-f 配合使用

  • \-f:依据 \-d 的分隔字符将信息分割为数段,取出指定的段

  • \-c:以字符为单位,取出固定的字符区间

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 示例1:从PATH变量中取出第5个路径
[dmtsai@study ~]$ echo ${PATH}
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
[dmtsai@study ~]$ echo ${PATH} | cut -d ':' -f 5
/home/dmtsai/.local/bin

# 同时取出第3和第5段
[dmtsai@study ~]$ echo ${PATH} | cut -d ':' -f 3,5
/usr/local/sbin:/home/dmtsai/.local/bin

# 示例2:从export输出中,去掉前11个字符,只保留变量部分
[dmtsai@study ~]$ export | cut -c 12-
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/home/dmtsai"
HOSTNAME="study.centos.vbird"

# 示例3:从last的输出中只提取登录用户名
[dmtsai@study ~]$ last | cut -d ' ' -f 1

注意:cut 在处理多空格相连的数据时会比较吃力,这种场景可以考虑使用 awk 来处理。

grep

grep 是分析一行信息,如果当中有我们需要的信息,就将该行拿出来,是非常常用的文本查找工具。

语法格式:

  • grep \[\-acinv\] \[\-\-color=auto\] \&\#39;搜索字符串\&\#39; filename

参数说明

  • \-a:将 binary 文件以 text 文件的方式搜索数据

  • \-c:计算找到搜索字符串的次数

  • \-i:忽略大小写的差异

  • \-n:顺便输出行号

  • \-v:反向选择,即显示出没有搜索字符串内容的那一行

  • \-\-color=auto:将找到的关键字部分加上颜色显示

示例

1
2
3
4
5
6
7
8
9
10
11
# 示例1:从last输出中找出包含root的行
[dmtsai@study ~]$ last | grep 'root'

# 示例2:反向过滤,找出不包含root的行
[dmtsai@study ~]$ last | grep -v 'root'

# 示例3:组合使用,找出root的登录记录,只提取用户名
[dmtsai@study ~]$ last | grep 'root' | cut -d ' ' -f1

# 示例4:在配置文件中查找包含MANPATH的行
[dmtsai@study ~]$ grep --color=auto 'MANPATH' /etc/man_db.conf

二、排序命令:sort、wc、uniq

这类命令可以帮我们对数据进行排序、去重和统计,非常适合用来做数据汇总。

sort

sort 可以帮我们进行排序,支持不同的数据类型排序,比如数字和文字的排序规则是不同的。

语法格式:

  • sort \[\-fbMnrtuk\] \[file or stdin\]

参数说明

  • \-f:忽略大小写的差异

  • \-b:忽略最前面的空白字符部分

  • \-M:以月份的名字来排序

  • \-n:使用纯数字进行排序(默认是以文字形态来排序)

  • \-r:反向排序

  • \-u:相当于 uniq,相同的数据中,仅出现一行代表

  • \-t:分隔符号,默认是用 tab 键来分隔

  • \-k:以指定的区间来进行排序

示例

1
2
# 对/etc/passwd的账号进行默认排序
[dmtsai@study ~]$ sort /etc/passwd

uniq

如果排序完成后,想要将重复的数据仅列出一个,就可以使用 uniq,这个命令会删除重复的行。

语法格式:

  • uniq \[\-ic\]

参数说明

  • \-i:忽略大小写字符的不同

  • \-c:进行计数

注意:uniq 只能去掉相邻的重复行,所以使用前需要先对数据进行排序!

示例

1
2
3
4
5
6
7
8
# 示例1:统计每个用户的登录次数
[dmtsai@study ~]$ last | cut -d ' ' -f1 | sort | uniq -c
1
6 (unknown
47 dmtsai
4 reboot
7 root
1 wtmp

wc

wc 可以帮我们统计文件的整体信息,比如行数、字数、字符数。

语法格式:

  • wc \[\-lwm\]

参数说明

  • \-l:仅列出行

  • \-w:仅列出多少字(英文单字)

  • \-m:多少字符

示例

1
2
3
4
5
6
7
# 示例1:统计/etc/man_db.conf的行数、字数、字符数
[dmtsai@study ~]$ cat /etc/man_db.conf | wc
131 723 5171
# 输出的三个数字分别代表:行、字数、字符数

# 示例2:统计当前系统的登录总人次
[dmtsai@study ~]$ last | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' |wc -l

三、双重重定向:tee

我们知道 \&gt; 重定向会将数据全部写入文件,屏幕上就看不到输出了。而 tee 可以实现双向重定向,它会同时将数据流传送到文件和屏幕,这样既可以保存结果,又可以在屏幕上看到输出,方便后续的管线处理。

语法格式:

  • tee \[\-a\] file

参数说明

  • \-a:以累加的方式,将数据加入文件当中,默认是覆盖

示例

1
2
3
4
5
6
7
8
# 示例1:将last的输出保存到文件,同时继续处理输出
[dmtsai@study ~]$ last | tee last.list | cut -d " " -f1

# 示例2:将ls的输出保存到文件,同时屏幕显示
[dmtsai@study ~]$ ls -l /home | tee ~/homefile | more

# 示例3:累加的方式写入文件
[dmtsai@study ~]$ ls -l / | tee -a ~/homefile | more

四、字符转换命令:tr、col、join、paste、expand

这类命令可以帮我们对字符、文本格式进行转换和合并,处理各种格式的文本数据。

tr

tr 可以用来转换字符,比如大小写转换、删除字符等。

语法格式:

  • tr \[\-ds\] SET1 \.\.\.

参数说明

  • \-d:删除信息当中的指定字符串

  • \-s:取代掉重复的字符

示例

1
2
3
4
5
6
7
8
# 示例1:将last的输出全部转成大写
[dmtsai@study ~]$ last | tr '[a-z]' '[A-Z]'

# 示例2:删除/etc/passwd中的冒号
[dmtsai@study ~]$ cat /etc/passwd | tr -d ':'

# 示例3:删除DOS文件的断行字符
[dmtsai@study ~]$ cat ~/passwd | tr -d '\r' > ~/passwd.linux

col

col 可以用来将 tab 键转换成对应的空白键,让文本显示更整齐。

语法格式:

  • col \[\-xb\]

参数说明

  • \-x:将 tab 键转换成对等的空白键

示例

1
2
# 将文件中的tab转换成空格,方便查看
[dmtsai@study ~]$ cat /etc/man_db.conf | col -x | cat -A | more

join

join 是用来处理两个文件之间的数据,它会将两个文件中,有相同数据的那一行合并在一起,非常适合用来关联两个相关的文件。

语法格式:

  • join \[\-ti12\] file1 file2

参数说明

  • \-t:默认以空白字符分隔数据,比对第一个字段的数据,如果相同就将两行合并

  • \-i:忽略大小写的差异

  • \-1:代表第一个文件要用哪个字段来分析

  • \-2:代表第二个文件要用哪个字段来分析

注意:使用 join 之前,需要先对处理的文件进行排序,否则有些比对的项目会被略过!

示例

1
2
3
4
5
6
7
8
9
10
11
# 示例1:合并passwd和shadow文件,按账号关联
[root@study ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash:$6$wtbCCce/PxMeE5wm$KE2IfSJr...:16559:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:16372:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:16372:0:99999:7:::

# 示例2:通过GID关联passwd和group文件
[root@study ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
0:root:x:0:0:root:/root:/bin/bash:root:x:0:
1:bin:x:1:1:bin:/bin:/sbin/nologin:bin:x:1:
2:daemon:x:2:2:daemon:/sbin:/sbin/nologin:daemon:x:2:

paste

paste 比 join 简单很多,它不需要比对数据,直接将两个文件的行按顺序贴在一起,中间用 tab 分隔。

语法格式:

  • paste \[\-d\] file1 file2

参数说明

  • \-d:后面可以接分隔字符,默认是以 tab 来分隔

  • \-:如果 file 部分写成 \-,表示来自 standard input 的数据

示例

1
2
3
4
5
6
7
8
# 示例1:直接将passwd和shadow的行贴在一起
[root@study ~]# paste /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash root:$6$wtbCCce/PxMeE5wm$KE2IfSJr...:16559:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin bin:*:16372:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:16372:0:99999:7:::

# 示例2:组合使用,将三个文件的内容贴在一起
[root@study ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3

expand

expand 专门用来将 tab 键转换成空白键,还可以自定义 tab 对应的空白字符数量。

语法格式:

  • expand \[\-t\] file

参数说明

  • \-t:后面可以接数字,定义一个 tab 按键代表多少个字符,默认是 8 个

示例

1
2
3
4
5
# 示例:将配置文件中的tab转换成6个空格
[dmtsai@study ~]$ grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 6 - | cat -A
MANPATH_MAP /bin /usr/share/man$
MANPATH_MAP /usr/bin /usr/share/man$
MANPATH_MAP /sbin /usr/share/man$

五、划分命令:split

如果你有大文件想要拆分成小文件,比如要拷贝到 U 盘或者发送邮件,split 就可以帮你把大文件按大小或者行数分割成多个小文件。

语法格式:

  • split \[\-bl\] file PREFIX

参数说明

  • \-b:后面可接欲分割成的文件大小,可加单位,例如 b, k, m 等

  • \-l:以行数来进行分割

  • PREFIX:代表分割后文件的前置字符,作为分割文件的前导文字

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 示例1:将services文件按300K分割
[dmtsai@study ~]$ cd /tmp; split -b 300k /etc/services services
[dmtsai@study tmp]$ ll -k services*
-rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesaa
-rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesab
-rw-rw-r--. 1 dmtsai dmtsi 81410 Jul 9 22:52 servicesac

# 示例2:分割后的文件可以用cat合并
[dmtsai@study tmp]$ cat services* >> servicesback

# 示例3:将ls的输出按10行分割成小文件
[dmtsai@study tmp]$ ls -al / | split -l 10 - lsroot
[dmtsai@study tmp]$ wc -l lsroot*
10 lsrootaa
10 lsrootab
4 lsrootac
24 total

六、参数代换:xargs

很多命令其实并不支持管线命令,无法直接接收前一个命令的输出作为参数,这时候 xargs 就可以派上用场了。它可以读入 stdin 的数据,将其分隔成参数,传递给后面的命令。

语法格式:

  • xargs \[\-0epn\] command

参数说明

  • \-0:如果输入的 stdin 含有特殊字符,这个参数可以将它们还原成一般字符

  • \-e:EOF 的意思,后面接一个字符串,当 xargs 分析到这个字符串时,就会停止继续工作

  • \-p:在执行每个命令的 argument 时,都会询问使用者的意思

  • \-n:后面接次数,每次 command 命令执行时,要使用几个参数

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 示例1:对前3个账号执行id命令,每次处理一个参数
[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
uid=0(root) gid=0(root) groups=0(root)
uid=1(bin) gid=1(bin) groups=1(bin)
uid=2(daemon) gid=2(daemon) groups=2(daemon)

# 示例2:执行前询问确认
[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id
id root ?...y
uid=0(root) gid=0(root) groups=0(root)
id bin ?...y

# 示例3:查到sync账号就停止处理
[dmtsai@study ~]$ cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -n 1 id

# 示例4:找出特殊权限的文件,并用ls列出详细信息
[dmtsai@study ~]$ find /usr/sbin -perm /7000 | xargs ls -l
-rwx--s--x. 1 root lock 11208 Jun 10 2014 /usr/sbin/lockdev
-rwsr-xr-x. 1 root root 113400 Mar 6 12:17 /usr/sbin/mount.nfs
-rwxr-sr-x. 1 root root 11208 Mar 6 11:07 /usr/sbin/netreport