1

I am having a shell script, which will start processes and kills the process. It is accepting the processes names as arguments. Need to find the pid and kill those.

Initially, it was like

for procname in ${@};do
    pkill -f $procname
done

Idk why, it is not killing all the processes passed to it. Now, I'm looking something like this

for procname in ${@};do
  IFS=$"\n"; echo
    (ps auxw | awk -v proc="$procname" -v preserve="${0##*/}" \
       '$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2}')
done

I'm trying to print the pid in above code, but I need kill command and it should be good, if it works without for loop

process names will contains . like com.abc.def.pqr.xyz

2 Answers2

4

pkill -f -- "$regex" kills processes whose arg list (for those processes that executed a command, or have an ancestor that did) joined with spaces (same as reported by standard ps -f or BSD ps u) matches the given extended regular expression (always excluding itself).

So all you need here is to join the positional parameters with |:

IFS='|'
pkill -f -- "$*"

To match on process names instead of arg list, remove the -f. Note however that on Linux, the length of process names is limited to 15 bytes, so can't possibly be com.abc.def.pqr.xyz. Also note that . is a regular expression operator that matches any single character, so to match process arg lists that contain that (and not comXabcYdefZpqr+xyz as well for instance), you'd need a com\.abc\.def\.pqr\.xyz regular expression.

0

I appreciate @Stéphane Chazelas answer. Since I am getting arguments for this shell script from JAVA and they are space separated and they contain character . in process names. I figured it out like this..

temp=()
for procname in ${@}; do
    temp+=$(jps -ml | grep $procname | grep -v grep | awk '{print $1 " "}')
done
kill -9 $temp
ilkkachu
  • 138,973
  • 1
    java may invoke a shell to interpret some shell code such as yourscript name1 name2, where those process names are indeed space-separated, but that's just because it happens to be that in the shell language, space is used to delimit command arguments. Your script will not receive the process names space separated it will receive them as different arguments ($1, $2...) and "$*" can be used to join those arguments with the first character of $IFS. – Stéphane Chazelas Jun 29 '22 at 08:38
  • 1
    Your code would only work in the zsh shell. In ksh93/bash, you'd need to quote all the variables and also use temp+=( "$(...)" ) instead of temp+=$(...) which for those shells would be the same as temp[0]+=$(...). In zsh, you can also use ${(j[|])argv} to join the positional parameters with | without having to modify $IFS. – Stéphane Chazelas Jun 29 '22 at 08:40
  • 1
    Note that the re in grep stands for regular expression, so . would still be treated as a regexp operator there. – Stéphane Chazelas Jun 29 '22 at 08:41
  • as long as that jps .. | awk pipeline outputs just a process id number, it should work in Bash (in the usual cases) even with using temp as a scalar and relying on word-splitting. But then the temp=() initialization is confusing, as you're not using temp as an array here. – ilkkachu Jun 29 '22 at 09:19
  • @ilkkachu, Ah, I hadn't seen the " " appended at the end of awk's output. Yes, then $temp (same as ${temp[0]}) would then be subject to split+glob in bash as it's not quoted, and assuming $IFS contains the space character and doesn't contain digits, it should work. – Stéphane Chazelas Jun 29 '22 at 09:37
  • @ilkkachu I am using temp as an array and appending each pid(with space) to temp in for. Then at last, I am sending those pid's to kill command – Shashank Gb Jun 29 '22 at 11:35
  • @ShashankGb, ... well, yes. That's not an array, that's a string. You are initializing temp as an array (with temp=()) and then only using the first element of the array. That's what the comments above tried to tell you. There is a difference, and you're only getting away with it because your values don't contain whitespace so you can rely on word splitting without messing everything up. You could remove the initial assignment, or change it to just temp=. Or heck, you could change it to temp=( '' foo bar ), and it'd still do the same. Assuming Bash for the whole time, of course. – ilkkachu Jun 29 '22 at 11:43
  • @StéphaneChazelas @ilkkachu Gotcha !!! lots of info, thx – Shashank Gb Jun 29 '22 at 11:55