0

I have a for loop to get the list of PID's and kill each PID. I want to display the entire line of PS output and write it to the /tmp/outfile . But from each line of PS output each field(PID,PPID,...) is written along with a new line in the /tmp/outfile. So if PS output has three lines as output i want to log these three lines into /tmp/outfile but it's breaking each field in the line and adding a new line. how can i do it.

for list in `ps -ef | grep "${process_name}" | grep -v "${SCRIPTNAME}" | grep -v grep`
do
     echo "$list" >> $CUSTOM_TMP/test5566
     PID=`echo $list | awk '{print $2}'`
     kill -TERM "$list"
done
Arav
  • 4,957
  • 23
  • 77
  • 123

6 Answers6

3

Your for loop does not iterate the lines but each individual field. Also your kill command was slightly wrong. Just change your code to something like:

ps -ef | grep "${process_name}" | grep -v "${SCRIPTNAME}" | grep -v grep | while read list
do
     echo "$list" >> $CUSTOM_TMP/test5566
     PID=`echo $list | awk '{print $2}'`
     kill -TERM "$PID"
done
macgarden
  • 361
  • 2
  • 2
  • Thanks a lot for the info. If the PS output has no record found i want to write it to the log file. I tried the below way and it's not working. if [ "${list}" = "" ]; then echo "No Process Name found - Grep no records found" fi – Arav Jun 07 '10 at 00:47
  • Also if the kill command fails i want to redirect the error output to a variable and write it to a log file using a custom API. The problem here if the PS error output has multiple lines when i move it to the variable it replaces the new line with space. Not sure how can i correct this. with APILOG function i can pass only variable as arguments. kill -TERM "$PID" 2> $CUSTOM_TMP/error_kill if [ $? -ne 0 ]; then ERROR=$(<$CUSTOM_TMP/error_kill) WriteAPILog ERROR "Error Message: $ERROR" rm $CUSTOM_TMP/error_kill fi – Arav Jun 07 '10 at 00:48
1

Isn't it easier to use the killall command for what you are trying to do?

Unknown
  • 5,722
  • 5
  • 43
  • 64
  • process name is passed as argument to the script. There might be 2 or 3 processes with same name so i am trying to kill it. If i do the above way instead of killall what i can do – Arav Jun 04 '10 at 07:40
  • Probably, but the OP wants to do it with a shell script :) – Tim Post Jun 04 '10 at 07:54
1

No need for a loop at all. And this uses tee to write your temp file.

list=$(ps -ef | grep "${process_name}" | grep -v "${SCRIPTNAME}" | grep -v grep | tee $CUSTOM_TMP/test5566 | awk '{printf "%s ", $2')
kill -TERM $list
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • Thanks a lot for the info. If the PS output has no record found i want to write it to the log file. I tried the below way and it's not working. if [ "${list}" = "" ]; then echo "No Process Name found - Grep no records found" fi – Arav Jun 07 '10 at 00:48
  • Also if the kill command fails i want to redirect the error output to a variable and write it to a log file using a custom API. The problem here if the PS error output has multiple lines when i move it to the variable it replaces the new line with space. Not sure how can i correct this. with APILOG function i can pass only variable as arguments. kill -TERM "$PID" 2> $CUSTOM_TMP/error_kill if [ $? -ne 0 ]; then ERROR=$(<$CUSTOM_TMP/error_kill) WriteAPILog ERROR "Error Message: $ERROR" rm $CUSTOM_TMP/error_kill fi – Arav Jun 07 '10 at 00:49
  • @arav: It would be easier to read if you posted your followup code as an edit to your original question. As for your `if [ "${list}" = "" ]` snippet, I see no problem with it, assuming the `fi` is intended to be on a separate line (if not you need to put a semicolon before it). By the way "it's not working" is not at all helpful. We can be much better at helping you if you include error messages and specific ways in which the results differ from what you expect. I don't know how your custom API works, but here is how Bash works: `variable=$( – Dennis Williamson Jun 07 '10 at 02:03
  • ...first `echo` outputs all the contents of the file on one line separated by one space per "word" (multiple spaces are collapsed into one). The second `echo` outputs the contents of the file in a format similar to the original file. The quotation marks preserve the newlines and any extra whitespace. – Dennis Williamson Jun 07 '10 at 02:12
0

You want to run ps before looping:

ps -ef | grep $"{process_name}" | grep -v "${SCRIPTNAME}" | grep -v grep > $CUSTOM_TMP/test5566 2>/dev/null

for PID in `cat $CUSTOM_TMP/test5566 | awk '{print $2}'`; do
      kill -TERM $PID
done
rm -f $CUSTOM_TMP/test5566

I would also insert some sanity, possibly using wc to make sure the file actually got some data from ps.

Tim Post
  • 33,371
  • 15
  • 110
  • 174
  • I just [discovered](https://stackoverflow.com/election/1) you were *NIX programmer! The `for PID in `cat foo | awk` looks a bit horrible. I would go for `while read -r PID; do ... done < <(awk '{print $2}' $CUSTOM_TMP/test5566`. That is, using [process substitution](https://stackoverflow.com/a/31703275/1983854). – fedorqui Mar 13 '18 at 10:54
0

Just move the awk part to the top line, otherwise your code is fine.

for list in `ps -ef | grep "${process_name}" | grep -v "${SCRIPTNAME}" | grep -v grep | awk '{print $2}`

do
     echo "$list" >> $CUSTOM_TMP/test5566
     PID=`echo $list`
     kill -TERM "$list"
done
Daniel t.
  • 965
  • 11
  • 18
0

For a one liner - if your system has pgrep --

pgrep -d ' ' ${process_name} > kill.log && kill -TERM $(< kill.log)
jim mcnamara
  • 16,005
  • 2
  • 34
  • 51