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

4
  • 1
    If your script is also starting the processes, why don't you save the PIDs so that you easily can terminate them later?
    – Kusalananda
    Jun 24, 2022 at 11:48
  • Yes, that can be possible. But these arguments are coming from Java. So, It will decide which process needs to kill or which process won't Jun 24, 2022 at 11:52
  • Does the code as posted actually run? The parser should refuse the assignment to $procname Jun 24, 2022 at 12:37
  • @StephenBoston My bad, I didn't copy pasted the code. Corrected now... :) Jun 27, 2022 at 5:04

2 Answers 2

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
9
  • 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. Jun 29, 2022 at 8: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. Jun 29, 2022 at 8:40
  • 1
    Note that the re in grep stands for regular expression, so . would still be treated as a regexp operator there. Jun 29, 2022 at 8: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, 2022 at 9: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. Jun 29, 2022 at 9:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .