命令的组合使用
1.查询当前整个系统每个进程的线程数
我们经常遇到这样的问题,比如某台服务器的CPU 使用率飙升,通过top命令查看是某个程序(例如java)占用的cpu比较大,现在需要查询java各个进程下的线程数情况。可以通这一个命令组合实现:
for pid in $(ps -ef|grep -v grep|grep "java"|awk '{print $2}');do echo ${pid} > /tmp/a.txt ;cat /proc/${pid}/status|grep Threads > /tmp/b.txt ; paste /tmp/a.txt /tmp/b.txt;done|sort -k3 –rn
先解释下这个脚本:
#这部分是获取${pid}变量为 java 进程的 pid 号。
for pid in $(ps -ef|grep -v grep|grep java |awk '{print $2}')
这部分是将 java 进程的 pid 号都打印到/tmp/a.txt 文件中。
echo ${pid} > /tmp/a.txt
这部分是将各个 pid 进程号下的线程信息打印到/tmp/b.txt 文件中。
cat /proc/${pid}/status|grep Threads > /tmp/b.txt
这部分是以列的形式展示a.txt和b.txt文件中的信息。
paste /tmp/a.txt /tmp/b.txt
这部分是对输出的信息进行排序,其中,-k3 表示以第三列进行排序,“-rn”表示降序排列。
sort -k3 -rn
将上面命令组合放入系统执行完毕后,输入内容如下:
从输出可以看出,第一列显示的是 java 的进程号,最后一列显示的每个 java 进程对应的线程数量。这个例子是一个for循环加上ps命令和sort命令综合应用的实例。
2.如何检测系统中的僵尸进程并kill掉
要查找系统中的僵尸进程,有多种方法,这里给出一种命令行探测僵尸进程的方法:
[root@qu ~]# ps -e -o stat,ppid,pid,cmd | egrep '^[Zz]'
Z 10808 10812 [java] <defunct>
介绍下用到的几个参数:
- -e:参数用于列出所有的进程
- -o:参数用于设定输出格式,这里只输出进程的 stat(状态信息)、ppid(父进程 pid)、pid(当前进程的 pid),cmd(即进程的可执行文件。
- egrep:是 linux 下的正则表达式工具
- ‘[Zz]’:这是正则表达式,表示第一个字符的位置,[Zz],表示小写 z或者大写的Z字母,即表示第一个字符为Z或者z开头的进程数据,只所以这样是因为僵尸进程的状态信息以Z 或者z字母开头。
找到僵尸进程的 pid 后,直接通过”kill -9 pid“命令杀掉即可,但是如果僵尸进程很多的话,就会很繁琐,因此,还需要一个批量删除僵尸进程的办法:
ps -e -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9
这是个命令组合,通过管道实现命令的组合应用。“grep -e”相当于 egrep命令。“awk ‘{print $2}’ ”是将前面命令的输出信息进行过滤,仅仅输出第二列的值,而第二列就是进程的 ppid。“xargs kill -9”这是将得到的 ppid 传给“kill -9”作为参数,也就是kill 掉这些ppid。xargs命令可以将标准输入转成各种格式化的参数,这里是将管道的输出内容作为参数传递给kill命令。
其实这个命令组合是将僵尸进程的父进程杀掉,进而关闭僵尸进程的,为什么要这么做呢,其实一般僵尸进程很难直接用kill 杀死,因为僵尸进程已经是死掉的进程,它不能再接收任何信号。所以,需要通过 kill 僵尸进程的父进程,这样父进程杀掉后,僵尸进程就成了”孤儿进程”,而所有的孤儿进程都会交给系统的 1 号进程(init 或 systemd)收养,1 号进程会周期性地去调用wait系统调用来清除这些僵尸进程。因此,我们可以发现,父进程杀掉之后,僵尸进程也跟着消失,其实是1号进程作用的结果!
3.如何查看当前占用CPU 或内存最多的几个进程
这个应用需求在服务器的问题排查和故障处理上使用率非常高,要获取这些信息,只需要一些命令组合即可实现,可以说非常简单。
1)获取当前系统占用CPU最高的前10个进程最简单的方式是通过ps命令组合实现,例如:
[root@qu ~]# ps aux|head -1;ps aux|sort -rn -k3|head -10
该命令组合主要分为两个部分:
- ps aux|head -1
- ps aux|sort -rn -k3|head -10
其中,第一句主要是为了获取标题(USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND)信息。而“head:-N”可以指定显示的行数,默认显示 10 行。
第二个命令是一个输出加排序组合,ps 参数的 a 指代 all,表示所有的进程,u 指代 user id,就是执行该进程的用户
id,x
指代显示所有程序,不以终端机来区分。
接下来是 sort 命令,其中:
- r 指代 reverse,这里是指反向比较结果,输出时默认从小到大,反向后从大到小。
- n 指代 numberic sort,根据其数值排序。
- k 代表根据哪一列进行排序,后面的数字 3 表示按照第 3 列排序。本例中,可以看到%CPU 在第 3 个位置,因此k3 表示根据%CPU 的数值进行由大到小的排序。
接下来的“|”为管道符号,将查询出的结果导到下面的命令中进行下一步的操作。最后的“head -10”命令获取默认前 10 行数据。
2)获取当前系统占用内存最高的前10个进程
同理,要获取系统占用内存最高的前10个进程,方法与获取cpu方法一致,命令组合修改为如下即可:
[root@qu ~]# ps aux|head -1;ps aux|sort -rn -k4|head -10
这里仅仅修改了k3位k4,4代表第4列排序。本例中,可以看到%MEM在第4个位置,因此k4表示根据% MEM的数值进行由大到小的排序。
4.如何对文件进行连接、合并、排序、去重
4.1.文件连接命令 join
join 命令用于将两个文件中,指定列中内容相同的行连接起来。找出两个文件中,指定列内容相同的行,并加以合并,再输出到标准输出设备。
常用的参数以及含义如下表所示:
参数 | 含义 |
-t | join 默认以空格符分隔数据,并且比对第一个字段的数据,如果两个文件相同,则将两笔数据联成一行,且第一个字段放在行首 |
-i | 忽略大小写的差异 |
-1 | 这个是数字的 1 ,代表第一个文件要用哪个字段来分析的意思 |
-2 | 代表第二个文件要用哪个字段来分析的意思 |
看一个例子:file1 文件的内容:
[root@localhost ~]# cat file1.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
file2文件的内容:
[root@localhost ~]# cat file2.txt
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mem:x:8:
要从 file1.txt 和 file2.txt 中可以看出,file1.txt 中以“:“分割的第三列和 file2.txt 中以“:“分割的第三列内容相同,因此这两个文件可以合并整合在一起,看下面这个操作:
[root@localhost ~]#join -t ':' -1 3 file1.txt -2 3 file2.txt
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:
3:adm:x:4:adm:/var/adm:/sbin/nologin:sys:x:
4:lp:x:7:lp:/var/spool/lpd:/sbin/nologin:adm:x:
5:sync:x:0:sync:/sbin:/bin/sync:tty:x:
6:shutdown:x:0:shutdown:/sbin:/sbin/shutdown:disk:x:
可以看出,通过-t选项指定了分隔符后,输出的内容是将file1.txt文件的第三列和file2.txt 文件的第三列进行整合的结果,两个文件合并后,相同的字段部分被移动到每行最前面了。
4.2.合并文件列命令paste
paste 命令用于合并文件的列。它会把每个文件以列对列的方式,一列列地加以合并。paste 比join 简单很多,它其实就是直接将两个文件中相同的两行贴在一起,且中间以 [tab]键隔开而已。
例如对上面的 file1.txt 和file2.txt 进行 paste 合并,执行结果如下:
[root@qu ~]# paste file1.txt file2.txt
root:x:0:0:root:/root:/bin/bash root:x:0:
bin:x:1:1:bin:/bin:/sbin/nologin bin:x:1:
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:x:2:
adm:x:3:4:adm:/var/adm:/sbin/nologin sys:x:3:
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin adm:x:4:
sync:x:5:0:sync:/sbin:/bin/sync tty:x:5:
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown disk:x:6:
halt:x:7:0:halt:/sbin:/sbin/halt lp:x:7:
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin mem:x:8:
接着,再看一个组合例子:
[root@qu ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3
root:x:0:0:root:/root:/bin/bash root:$6$itBvz.u4iA5xf22B$LIlL6/QaOUOlEk8THDtlVYv0jU9ByBDIqyaKqaXBvpLbKnez359YtwnrRaXkHdkY9t/lhPe5xzvmfGaprwFEh/::0:99999:7::: root:x:0:
bin:x:1:1:bin:/bin:/sbin/nologin bin:*:18353:0:99999:7::: bin:x:1:
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:18353:0:99999:7::: daemon:x:2:
这个例子的重点在那个“-”的使用,那玩意代表标准输入,在这里会接收/etc/group 的内容,因为通过“cat /etc/group”将此文件内容送到了标准输入,而“-”刚好接收了这个内容。因此,这个组合其实是三部分文件内容的合并,分别是/etc/passwd、/etc/shadow和/etc/group三个文件内容合并的结果,而每行内容中通过默认的[tab]键隔开。
4.3.文本内容排序命令sort
sort 这个命令很好用,主要用做排序,基本使用格式为:
sort [-t 分隔符] [-kn1,n2] [-nru]
参数含义如下表所示:
参数 | 含义 |
-n | 使用纯数字进行排序,默认是以字母顺序来排序的 |
-r | 反向排序 |
-u | 就是 uniq ,相同的数据中,仅出现一行代表 |
-t | 分隔符,默认是用 [tab] 键来分隔 |
-k | 以那个区间(field)来进行排序的意思 |
先看最简单的一个例子:
[root@qu ~]# cat /etc/passwd | sort | head
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
halt:x:7:0:halt:/sbin:/sbin/halt
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
这是最简单的一个sort排序,没指定任何参数,所以默认以英文字母顺序进行排序, head是默认显示前10行数据,要显示指定行数据,可以通过“head -N”实现。
继续看下面这个例子:
[root@qu ~]# cat /etc/passwd | sort -t ':' -k3 -n | head
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
这个例子是通过指定分隔符’:‘,然后对指定的列进行排序,k3表示以’:'作为分隔符的第三列,也就是以第三列为准进行排序,由于第三列都是数字,所以还需要“-n”参数。
4.4.检查并删除文件中的重复行命令uniq
uniq主要用于检查及删除文本文件中重复出现的行,一般与sort命令结合使用,常用参数如下表所示:
参数 | 含义 |
-c 或–count | 在每列旁边显示该行重复出现的次数 |
-d:或–repeated | 仅显示重复出现的行列 |
看下面例子:这是ixdbafile1 文件的内容:
[root@qu ~]# cat ixdbafile1
server 188
server 188
server 188
jenkins 66
jenkins 66
oracle 90
oracle 90
oracle 90
saybye 122
saybye 122
saybye 122
saybye 122
可以看到有重复行,并且重复行都是相邻的,要删除重复行,uniq 就派上用场了,看下面例子:
[root@qu ~]# uniq ixdbafile1
server 188
jenkins 66
oracle 90
saybye 122
可以看到,已经删除了重复行。如果要统计重复行出现的次数,加上“-c”参数即可,看下面这个例子:
[root@qu ~]# uniq ixdbafile1 -c
3 server 188
2 jenkins 66
3 oracle 90
4 saybye 122
上面的 ixdbafile1 文件有些特殊,因为实际使用中,重复行不可能都是相邻在一起的,那继续来看另一个文件内容:
[root@qu ~]# cat ixdbafile2
server 188
saybye 122
jenkins 66
server 188
saybye 122
jenkins 66
server 188
saybye 122
jenkins 66
oracle 90
redis 126
这是个重复行不相邻的文件,实际环境中,很多都是类似这样的文件,再通过uniq看看是否能够删除重复行,执行如下操作:
[root@qu ~]# uniq ixdbafile2
server 188
saybye 122
jenkins 66
server 188
saybye 122
jenkins 66
server 188
saybye 122
jenkins 66
oracle 90
redis 126
可以看到,文件原样输出了,也就是说 uniq 对这些重复行不相邻的内容无能为力了,怎么办呢,现在是时候该sort出场了,sort 我们知道是排序用的,那就先把这个文件进行排序,这样,重复行不就自动相邻了吗,看下面操作:
[root@qu ~]# sort ixdbafile2
jenkins 66
jenkins 66
jenkins 66
oracle 90
redis 126
saybye 122
saybye 122
saybye 122
server 188
server 188
server 188
经过 sort 排序后,重复行相邻了,接着通过管道后面接 uniq 命令即可过滤删除重复行了,看下面操作:
[root@qu ~]# sort ixdbafile2|uniq
jenkins 66
oracle 90
redis 126
saybye 122
server 188
果然,经过sort排序后,uniq又可以正常工作了,这也是为什么sort经常和uniq一起使用的原因了。
下面这个是使用了 uniq 的“-d”参数,也就是显示重复行有哪些:
[root@qu ~]# sort ixdbafile2|uniq -d
jenkins 66
saybye 122
server 188
几个简单例子,发现 uniq 很简单。