0

I have the following shell script:

#!/bin/bash

top -n 1 -p $(pgrep -d',' -f R) | grep R | awk '{if ($2 != "PID" && int($10) > 50) 
{
    kill_cmd = "echo kill " $1 " | bash -";
    system(kill_cmd);
}}'

If I change the system call to a print statement the resulting output looks as I expect: echo kill <some_pid> | bash - I am also able to run the output from the print statements without error.

The system call errors out stating: syntax error near unexpected token `('

The intent of the script is to use top to look at running R processes and kills them if they are using more than 50% of the system memory.

1
  • If the debugging print statement produces the expected output as you say it does then there is nothing in your script that would produce the error message you say it does so you are making a mistake somewhere in diagnosing/describing the problem. Add print "<" kill_cmd ">" before the system() call then run cat -v script; ./script and copy/paste the result into your question so we can see exactly the command you are running and the output plus error message it produces. Commented Jan 24, 2017 at 16:12

3 Answers 3

1

In your case below statements are wrong you don't need echo,| and bash -

kill_cmd = "echo kill " $1 " | bash -";
system(kill_cmd);

You can just use ( Note : make sure PID column in $1, it should be $2, I guess)

$ top -n 1 -p $(pgrep -d',' -f R) | 
  awk '/R/ && $2 != "PID" && int($10) > 50{system("kill " $2 )}'

Like below

$ awk 'BEGIN{system("date")}'
Tue Jan 24 12:41:08 IST 2017

Instead of calling system() every time, you can pipe it at the end

Either

$ top -n 1 -p $(pgrep -d',' -f R) | 
  awk '/R/ && $2 != "PID" && int($10) > 50{ print "echo kill " $2 }' | bash

OR

$ top -n 1 -p $(pgrep -d',' -f R) | 
  awk '/R/ && $2 != "PID" && int($10) > 50{ print  $2 }' | xargs kill -9

For example

$ awk 'BEGIN{for(i=1;i<=5;i++)print "echo test :"i; print "date"}' 
echo test :1
echo test :2
echo test :3
echo test :4
echo test :5
date

$ awk 'BEGIN{for(i=1;i<=5;i++)print "echo test :"i; print "date"}'  | bash
test :1
test :2
test :3
test :4
test :5
Tue Jan 24 12:31:43 IST 2017
Sign up to request clarification or add additional context in comments.

Comments

1

The intent of the script is to use top to look at running R processes and kills them if they are using more than 50% of the system memory.

For this purpose, I wouldn’t use pgrep nor top, nor any useless grep before awk.

ps aux | awk '$11 ~/R/ && $4 > 50 { system("kill " $2) }'

or

ps aux | awk '$11 ~/R/ && $4 > 50 { print $2 }' | xargs kill

This has been tested on Linux. Depending on the particular formatting of the output of ps in your system, the dollar parameters might be numbered differently (you might also want to instruct ps to use another output format or process selection by providing an argument different from aux.) Also, maybe the match ~/R/ should probably be refined, but it is the same you were using. xargs calls kill only once, after collecting the PIDs in one command line, unless there are too many of them, in which case xargs splits the PIDs into an appropriate number of kill invocations (impossible in this case, given that you cannot have tens of processes, each consuming more than 50% of the system memory...)

2 Comments

Great solution; thank you. Do you know what was causing my system call to fail?
In fact, no. I wasn’t able to reproduce the error and I suspect it was caused by some occasional typo, such as an unbalanced quote or the like. But if you simplify your command line, you also decrease the chances of such obscure mistakes. And please don’t forget to accept the answer if you like it...
0
#!/bin/bash

eval "$( 
   top -n 1 -p $(pgrep -d',' -f R) \
    | awk '
        /R/ && $10 >= 51 && $2 != "PID" { L = L " " $1 } 
        END { if ( L !~ /^$/) print "kill" L }
        '
    )"
  • eval call only once the systeme via a subshell for all PID to kill (kill allow to kill several pid passed as parameter
  • no need of a grep R followed by a awk, awk could filter with /R/
  • simple test could often be made as filter instead of a if inside structure
  • maybe add a levell of signal (eventually via variable passed to awk) for kill level

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.