简体   繁体   English

Bash脚本在for循环中杀死命令

[英]Bash script kill command in for loop

I want to kill all processes containing some string. 我想杀死所有包含一些字符串的进程。 I wrote script for doing this. 我为此编写了脚本。 However, when I execute it, it gets "Killed" signal after first iteration of for loop. 但是,当我执行它时,它会在for循环的第一次迭代后得到“杀死”信号。 This is my code: 这是我的代码:

#!/bin/bash

executeCommand () {
 local pname="$1";
 echo $HOSTNAME;
 local  search_terms=($(ps aux | grep $pname | awk '{print $2}'))
 for pros in "${search_terms[@]}";  do
     kill -9 "$pros"
     echo $pros
 done
exit
}

executeCommand "$1"  # get the string that process to be killed contains

I execute it like ./my_script.sh zookeeper . 我像./my_script.sh zookeeper一样执行它。 When I delete the line containing kill command, for loop executes until end, otherwise, after first kill command, I get as an output " Killed " and program exits. 当我删除包含kill命令的行时, for loop执行到结束,否则,在第一个kill命令之后,我将获得输出“ Killed ”,然后程序退出。

What is possible reason for this, and any other solution to reach my goal? 这可能是什么原因,还有其他解决方案可以达到我的目标吗?

The silly (faulty, buggy) way to do this is to add grep -v grep to your pipeline: 做到这一点的愚蠢的(错误的,错误的)方法是将grep -v grep添加到管道中:

# ${0##*/} expands to the name of the running script
# ...thus, we avoid killing either grep, or the script itself
ps aux | grep -e "$pname" | egrep -v "grep|${0##*/}" | awk '{print $2}'

The better way is to use a tool built for the job: 更好的方法是使用为该工作而构建的工具:

# pkill already, automatically, avoids killing any of its parent processes
pkill "$pname"

That said, matching processes by name is a bad practice to start with -- you'll also kill less yourproc.log or vim yourproc.conf , not just yourproc . 就是说,从名称开始匹配进程是一个坏习惯,一开始,您将杀死less yourproc.logvim yourproc.conf ,而不仅仅是yourproc Don't do it; 不要做 instead, use a proper process supervision system (upstart, DJB daemontools, Apple launchd, systemd, etc) to monitor your long-running daemons and kill or restart them when needed. 相反,请使用适当的过程监控系统(启动程序,DJB daemontools,Apple启动,systemd等)来监视长时间运行的守护程序,并在需要时将其杀死或重新启动。


By the way -- there's no need for a for loop at all: kill can be passed multiple PIDs on a single invocation, like so: 顺便说一句-有没有需要一个for循环都: kill都可以通过多种PID的上一个调用,就像这样:

# a bit longer and bash-specific, but avoids globbing
IFS=$'\n' read -r -d '' -a pids \
  < <(ps auxw | awk -v proc="$pname" -v preserve="${0##*/}" \
      '$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2 }' \
      && printf '\0')
kill -- "${pids[@]}"

...which could also be formulated as something like: ...也可以表述为:

# setting IFS and running `set -f` necessary to make unquoted expansion safe
( IFS=$'\n'; set -f; exec kill -- \
  $(ps auxw | awk -v proc="$pname" -v preserve="${0##*/}" \
    '$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2 }') )

grep will show , it's own process . grep将显示,这是自己的过程。 it should be removed using grep -v option 应该使用grep -v选项将其删除

Try like this 这样尝试

for i in ` ps -ef | grep "$pname" | grep -v grep | awk '{print $2}'`
do    
  kill -9 $i
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM