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

Shashank Gb
  • 111
  • 5

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.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
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
  • 133,243
  • 15
  • 236
  • 397
Shashank Gb
  • 111
  • 5
  • 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 `r`egular `e`xpression, 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
  • See [Why does my shell script choke on whitespace or other special characters?](https://unix.stackexchange.com/questions/131766/why-does-my-shell-script-choke-on-whitespace-or-other-special-characters) and [How can we run a command stored in a variable?](https://unix.stackexchange.com/q/444946/170373) – ilkkachu Jun 29 '22 at 11:44
  • @StéphaneChazelas \@ilkkachu Gotcha !!! lots of info, thx – Shashank Gb Jun 29 '22 at 11:55