linux 工具 -- pskill
在linux 中如果需要强制杀死进程, 通常需要先通过ps 命令查询到该进程id, 然后在通过kill 命令强制杀死进程. 在频繁地linux 运维管理过程中, 这些操作无疑是繁琐的, 因此笔者开发了pskill 命令, 用于快速杀死进程.
1. pskill 特色
- 使用方便, 结合了ps 和 kill 命令, 一步即可
- 提供用户交互, 让用户选择要删除的进程
- 防止误操作, 有最大进程限制
2. pskill 开发
2.1 pskill.pl 源码:
#!/usr/bin/perl
#Desc 强制杀死正在运行的进程,可同时杀死多个进程
#Auth zongf
#Date 2017-07-15
use Term::ANSIColor qw(:constants);
$Term::ANSIColor::AUTORESET = 1;
######################################## 子程序 ########################################
#打印注释信息
sub print_help{
#获取标签和注释
my($tag) = shift @_;
my($cmt) = shift @_;
#输出第一行注释
print BOLD BLUE "$tag: ";
print "$cmt\n";
#输出其它的注释
printf "%5s $_\n","" foreach @_;
}
#检查是否是查询帮助
sub check_help{
my $param = $ARGV[0];
if("-h" eq $param || "--help" eq $param){
&print_help("Desc","强制杀死当前正在运行的进程, 存在一次用户交互");
&print_help("Args","关键字列表");
&print_help("Exam","pskill tomcat: 选择杀死包含tomcat 关键字的进程",
"pskill tomcat nginx: 选择杀死包含tomcat 或 nginx 关键字的进程");
&print_help("Auth","zongf");
&print_help("Date","2017-07-15");
exit;
}
}
#desc 输出有颜色的字符串
#para1 接收至少两个参数以上,第一个参数为要格式化的字符串,之后的参数为要使用颜色的字符串
sub print_color(){
# 如果长度小于2, 那么不进行格式化输出,直接打印
if(@_ < 2){
print shift @_;
return;
}
#获取要格式化颜色的字符串
my $line = shift @_;
#获取要高亮的字符串数组
my @patterns = @_;
#获取要高亮显示的字符串数组,拼接正则模式
my $spectors = (shift @_) . '+';
foreach(@_){
$spectors .= "|$_+";
}
#按正则模式进行分组
my @arrays = split(/($spectors)/, $line);
#输出结果
for my $item(@arrays){
#直接使用@patterns 数组反向匹配,数组内插时,每个字符串直接会有空格
my $pattern = "@patterns";
#字符串中查找元素,如果有的话则高亮显示,否则正常显示
my $idx = index($pattern, $item);
if($idx > -1){
print BOLD RED $item;
}else{
print $item;
}
}
}
#格式化索引长度
#参数: 接收两个参数
# para1: 需要格式化的索引
# para2: 数组长度
#返回: [1 ]
sub fmt_idx{
return shift @_ if @_ < 2;
my ($str, $array_length) = @_;
my $length = length $array_length;
return sprintf "[%-${length}s] ", $str;
}
#杀死进程
sub kill_ps_line{
my $ps_line = shift @_;
my $pid = (split/\s+/,$ps_line)[1];
$cnt = kill 9, $pid;
if($cnt == 1){
print BOLD GREEN "[成功] "; printf "进程pid: %6d 强制杀死成功!\n",$pid;
} else {
print BOLD RED "[失败] "; printf "进程pid:%6d 强制杀失败!\n",$pid;
}
}
#获取用户输入,返回输入列表
sub get_user_choose{
print "\n[输入] 请输入您要杀死的进程序号,0表示所有: ";
chomp($choose=<STDIN>);
#判断用户输入是否只能是数字
unless($choose =~ /^(\s|[0-9]|\s)+$/){
print "[错误] 只能输入正整数\n";
exit;
}
#获取用户输入的序号列表
@ids = split(/\s+/, $choose);
@ids_asc = sort @ids;
# 判断输入是否包含0,确保0 只能单独出现
if(@ids_asc >1 && $ids_asc[0] ==0 ){
print "[错误] 0 表示全部, 只能单独使用\n";
exit;
}
#判断用户输入最大值最小值
if($ids_asc[-1] > (@lines +1) || $ids_asc[0] < 0){
print "[错误] 序号取值范围为 [0~ " . (@lines) . "]\n";
exit;
}
#如果只有一个元素,且为0
if(@ids == 1 && $ids_asc[0] ==0){
return (1 .. @lines);
}else{
return @ids;
}
}
######################################## 主程序 ########################################
&check_help;
#如果用户不传过滤参数,则直接退出程序
if(@ARGV <1){
print BOLD RED "[error] "; print "此命令需要至少一个参数作为筛选条件!\n";
exit;
}
#存储匹配模式,用户高亮输出
@patterns = @ARGV;
#进行端口号拼接
$names = shift @ARGV;
foreach (@ARGV){
$names .="|$_";
}
#如果参数不为空,则进行筛选
$ps_cmd = 'ps -ef | grep -v grep | grep -v kill9';
$ps_cmd .= " | grep -E \"" . $names ."\"" if defined $names;
@lines = `$ps_cmd`;
$length =@lines;
if($length < 1){
#没有符合条件时,直接退出程序
print "没有符合条件的进程运行\n";
exit;
} elsif ($length >10 ){
#做多一次性杀死10个进程
print "正在运行的进程:\n";
print foreach @lines;
printf "最多一次性杀死10个进程,而符合筛选条件的进程数为: %3d个,请精确筛选条件\n", $length;
exit;
} else{
#如果查出结果大于1个进程,则需要确认
#遍历查询结果
$lines_length = @lines;
for $idx (1 ... @lines){
print BOLD GREEN &fmt_idx($idx, $lines_length);
&print_color($lines[$idx-1], @patterns);
}
#获取用户选择的序号列表
@ids = &get_user_choose;
#按用户选择进行杀死进程
&kill_ps_line($lines[$_-1]) foreach @ids;
}
2.2 加密为二级制程序
- 使用笔者自己开发的perl2bin 工具将源文件加密为二进制程序, 并删除源程序
- 将二进制程序pskill 移动到某个环境变量目录, 笔者设置的环境变量目录为: /usr/local/bin/perl/
[admin@localhost perl]$ ls
pskill.pl
[admin@localhost perl]$ perl2bin pskill.pl
开始转换脚本:pskill.pl
[admin@localhost perl]$ ls
pskill pskill.pl
[admin@localhost perl]$ mv pskill /usr/local/bin/perl/
3. 测试
- pskill 工具会有一次用户交互过程, 需要用户选择要删除的索引号, 0 代表删除列出的所有进程
- pskill 为防止误操作, 所以限制每次最多删除10个进程
3.1 查看命令帮助
[admin@localhost perl]$ pskill -h
Desc: 强制杀死当前正在运行的进程, 存在一次用户交互
Args: 关键字列表
Exam: pskill tomcat: 选择杀死包含tomcat 关键字的进程
pskill tomcat nginx: 选择杀死包含tomcat 或 nginx 关键字的进程
Auth: zongf
Date: 2017-07-15
[admin@localhost perl]$ pskill --help
Desc: 强制杀死当前正在运行的进程, 存在一次用户交互
Args: 关键字列表
Exam: pskill tomcat: 选择杀死包含tomcat 关键字的进程
pskill tomcat nginx: 选择杀死包含tomcat 或 nginx 关键字的进程
Auth: zongf
Date: 2017-07-15
3.2. 删除单个进程
- 查询并选择杀死tomcat 进程
- 用户交互: 输入列表索引
[admin@localhost perl]$ pskill tomcat
[1] admin 3383 1 49 01:27 pts/1 00:00:06 /opt/app/jdk/jdk1.7.0_80/bin/java -Djava.util.logging.config.file=/opt/app/tomcat/tomcat-7-7080/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms516m -Xmx1024m -Xss1024K -XX:PermSize=512m -XX:MaxPermSize=512m -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/opt/app/tomcat/tomcat-7-7080/endorsed -classpath /opt/app/tomcat/tomcat-7-7080/bin/bootstrap.jar:/opt/app/tomcat/tomcat-7-7080/bin/tomcat-juli.jar -Dcatalina.base=/opt/app/tomcat/tomcat-7-7080 -Dcatalina.home=/opt/app/tomcat/tomcat-7-7080 -Djava.io.tmpdir=/opt/app/tomcat/tomcat-7-7080/temp org.apache.catalina.startup.Bootstrap start
[2] admin 3429 1 84 01:27 pts/1 00:00:05 /opt/app/jdk/jdk1.7.0_80/bin/java -Djava.util.logging.config.file=/opt/app/tomcat/tomcat-8-8080/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Djava.endorsed.dirs=/opt/app/tomcat/tomcat-8-8080/endorsed -classpath /opt/app/tomcat/tomcat-8-8080/bin/bootstrap.jar:/opt/app/tomcat/tomcat-8-8080/bin/tomcat-juli.jar -Dcatalina.base=/opt/app/tomcat/tomcat-8-8080 -Dcatalina.home=/opt/app/tomcat/tomcat-8-8080 -Djava.io.tmpdir=/opt/app/tomcat/tomcat-8-8080/temp org.apache.catalina.startup.Bootstrap start
[输入] 请输入您要杀死的进程序号,0表示所有: 1
[成功] 进程pid: %6d 强制杀死成功!
3.3 批量删除进程
[admin@localhost perl]$ pskill tomcat
[1] admin 3521 1 49 01:29 pts/1 00:00:04 /opt/app/jdk/jdk1.7.0_80/bin/java -Djava.util.logging.config.file=/opt/app/tomcat/tomcat-7-7080/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms516m -Xmx1024m -Xss1024K -XX:PermSize=512m -XX:MaxPermSize=512m -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/opt/app/tomcat/tomcat-7-7080/endorsed -classpath /opt/app/tomcat/tomcat-7-7080/bin/bootstrap.jar:/opt/app/tomcat/tomcat-7-7080/bin/tomcat-juli.jar -Dcatalina.base=/opt/app/tomcat/tomcat-7-7080 -Dcatalina.home=/opt/app/tomcat/tomcat-7-7080 -Djava.io.tmpdir=/opt/app/tomcat/tomcat-7-7080/temp org.apache.catalina.startup.Bootstrap start
[2] admin 3542 1 52 01:29 pts/1 00:00:03 /opt/app/jdk/jdk1.7.0_80/bin/java -Djava.util.logging.config.file=/opt/app/tomcat/tomcat-8-8080/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Djava.endorsed.dirs=/opt/app/tomcat/tomcat-8-8080/endorsed -classpath /opt/app/tomcat/tomcat-8-8080/bin/bootstrap.jar:/opt/app/tomcat/tomcat-8-8080/bin/tomcat-juli.jar -Dcatalina.base=/opt/app/tomcat/tomcat-8-8080 -Dcatalina.home=/opt/app/tomcat/tomcat-8-8080 -Djava.io.tmpdir=/opt/app/tomcat/tomcat-8-8080/temp org.apache.catalina.startup.Bootstrap start
[3] admin 3564 1656 0 01:30 pts/1 00:00:00 /usr/bin/perl ./pskill tomcat
[输入] 请输入您要杀死的进程序号,0表示所有: 1 2
[成功] 进程pid: 3521 强制杀死成功!
[成功] 进程pid: 3542 强制杀死成功!
3.4 杀死全部进程
- 用户交互时输入0, 表示删除查询到的所有进程
- 示例中nginx 进程由root 用户启动, 所以admin 用户无权杀死进程, 所以杀死进程失败
[admin@localhost perl]$ pskill tomcat nginx
[1] root 2974 1 0 00:27 ? 00:00:00 nginx: master process nginx
[2] nginx 2975 2974 0 00:27 ? 00:00:00 nginx: worker process
[3] admin 3629 1 59 01:31 pts/1 00:00:07 /opt/app/jdk/jdk1.7.0_80/bin/java -Djava.util.logging.config.file=/opt/app/tomcat/tomcat-7-7080/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms516m -Xmx1024m -Xss1024K -XX:PermSize=512m -XX:MaxPermSize=512m -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/opt/app/tomcat/tomcat-7-7080/endorsed -classpath /opt/app/tomcat/tomcat-7-7080/bin/bootstrap.jar:/opt/app/tomcat/tomcat-7-7080/bin/tomcat-juli.jar -Dcatalina.base=/opt/app/tomcat/tomcat-7-7080 -Dcatalina.home=/opt/app/tomcat/tomcat-7-7080 -Djava.io.tmpdir=/opt/app/tomcat/tomcat-7-7080/temp org.apache.catalina.startup.Bootstrap start
[4] admin 3647 1 47 01:31 pts/1 00:00:04 /opt/app/jdk/jdk1.7.0_80/bin/java -Djava.util.logging.config.file=/opt/app/tomcat/tomcat-8-8080/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Djava.endorsed.dirs=/opt/app/tomcat/tomcat-8-8080/endorsed -classpath /opt/app/tomcat/tomcat-8-8080/bin/bootstrap.jar:/opt/app/tomcat/tomcat-8-8080/bin/tomcat-juli.jar -Dcatalina.base=/opt/app/tomcat/tomcat-8-8080 -Dcatalina.home=/opt/app/tomcat/tomcat-8-8080 -Djava.io.tmpdir=/opt/app/tomcat/tomcat-8-8080/temp org.apache.catalina.startup.Bootstrap start
[5] admin 3658 1656 0 01:31 pts/1 00:00:00 /usr/bin/perl ./pskill tomcat nginx
[输入] 请输入您要杀死的进程序号,0表示所有: 0
[失败] 进程pid: 2974 强制杀失败!
[失败] 进程pid: 2975 强制杀失败!
[成功] 进程pid: 3629 强制杀死成功!
[成功] 进程pid: 3647 强制杀死成功!
Killed
[admin@localhost perl]$ psgrep nginx
[1] root 2974 1 0 00:27 ? 00:00:00 nginx: master process nginx
[2] nginx 2975 2974 0 00:27 ? 00:00:00 nginx: worker process
[admin@localhost perl]$