4

I am trying to find if a process is running or not, and if it is runing then I want to call a script or print something. I tried with the below few ways, but it gives me syntax error or command not found error.

APP_ID = ps -eaf | grep -i `whoami` | grep -i <process_name> | grep -i java | awk '{print$2}'

if[''!= '${APP_ID}'] then
    echo "Stopping instance $APP_ID"

I get the result as below:

test.sh: line 15: APP_ID: command not found
test.sh: line 17: if[!= ${APP_ID}]: command not found
Stopping instance 

What is wrong in the above script? And if it has some errors, then why does it print the echo in the if condition?

Also the below script fails saying test.sh: line 3: [ps: command not found

if [ps -eaf | grep -i `whoami` | grep -i <process_name> | grep -i java]; then
    echo 'stop'
fi

4 Answers 4

10

Your syntax has many problems:

  • remove spaces around "=" when setting a variable

    wrong:

    APP_ID = value
    

    right:

    APP_ID=value
    
  • to run a program and put its output into a variable, you need $(...) (preferred in bash, not available in sh) or backticks `command` (supported in bash and sh). (and remember that when assigning a variable, quotes are not needed, but in other cases they are important: command "$(command)")

    wrong:

    APP_ID=command
    

    right:

    APP_ID=$(command)
    
  • add spaces around everything when using "[", and you need a semicolon or newline after the "]". This is because "[" is a bash builtin command, and the non-builtin one is also known as "test" (see man test), which just like other commands, takes its arguments separated by space:

    wrong:

    if[x!= y] then echo hello world fi
    

    right:

    if [ x != y ]; then echo hello world; fi
    
  • use double quotes, not single quotes when you want to expand a variable

    wrong:

    if [ '' != '${APP_ID}' ]; then
    

    right:

    if [ '' != "${APP_ID}" ]; then
    
  • Also for the above example, you can use -n (non-empty) instead of comparing to empty string

    if [ -n "${APP_ID}" ]; then
    
  • And for the ps example, you don't need grep and awk:

    APP_ID=$(ps -C whoami --no-header --format 'pid')
    

And so here is the fixed up script:

APP_ID=$(ps -C whoami --no-header --format 'pid')

if [ -n "${APP_ID}" ]; then
    echo "Stopping instance $APP_ID"
fi
4
  • 1
    [ is a built in of bash. But behaves as if it is a separate command. On some shells it is. You can find [ in /usr/bin/[, and it has a man page. Commented Jul 13, 2016 at 9:09
  • Thanks for the reply. Do we need to provide the pid in the above script ? I just have the process name which I want to stop. I am very new to scripting and trying to learn hence please bear with me for the stupid questions.
    – user179309
    Commented Jul 13, 2016 at 9:10
  • @user179309 in the above script, it looks by name, just like you did with whoami, and the APP_ID will be a single or multi-line string including all the process ids (depending on how many processes are found).
    – Peter
    Commented Jul 13, 2016 at 9:15
  • @richard thanks, I guess you're right that I implied it's the same when it's not, so I fixed that.
    – Peter
    Commented Jul 13, 2016 at 9:19
5

This is easiest done with pgrep and pkill:

if pgrep process_name 2>/dev/null; then
  echo "Terminating process_name"
  pkill process_name
fi

As user @OrangeDog points out in the comments, there is the theoretical possibility of this shell code failing to terminate the process process_name if the process spawns inbetween the call to pgrep and pkill. In this case, pgrep would not detect the process and pkill would never execute. How much of a problem this is, I don't know. If the process spawns just after the statement, what can you do?

Just do

echo "terminating process_name (if it is running)"
pkill process_name

to be rid of the pesky race condition in any case.

8
  • Why bother checking beforehand?
    – OrangeDog
    Commented Jul 13, 2016 at 14:01
  • @OrangeDog Because in script in the question, the OP clearly tries to do the same.
    – Kusalananda
    Commented Jul 13, 2016 at 14:20
  • This has a race condition. The process you kill may not be the same one that you grepped for.
    – OrangeDog
    Commented Jul 13, 2016 at 14:22
  • @OrangeDog There is technically a race condition in there in terms of what PIDs gets signalled, true. But the signal with be delivered to the instances of process_name running while pkill is executing none the less. It would have been worse if I had taken the PIDs from pgrep and fed them to kill, which might have left some recently spawned instance of process_name running. This will not be the case here.
    – Kusalananda
    Commented Jul 13, 2016 at 14:25
  • @OrangeDog The "worst" thing that could happen is that process_name terminates before we get to pkill.
    – Kusalananda
    Commented Jul 13, 2016 at 14:28
1

I am not sure why but the above script was not giving any syntax issues but was not giving the process id also though the process was running.

I finally changed it as below and it works -

APP_ID=$(ps -ef | grep <app_name> | grep java | awk '{print $2}')

echo "Instance $APP_ID"
if [ -n "${APP_ID}" ]; then
    echo "Stopping instance $APP_ID"
fi

Thanks once again for the explanation and pointers.

@Peter I will check again the script you posted on why it is not working for me.

1
  • Don't do this ps … | grep … stuff, it's unreliable: sooner or later you'll end up killing an unrealted process with a resembling name. Use pgrep instead. Commented Jul 13, 2016 at 22:40
0

The command above will also catch the grep it self, so the command, in case of java process, should be

APP_ID=$(ps -ef | grep <app_name> | grep -v grep | awk '{print $2}')

echo "Instance $APP_ID"
if [ -n "${APP_ID}" ]; then
    echo "Stopping instance $APP_ID"
    kill $APP_ID   (or kill -9 $APP_ID)
fi

hope this helps.

You must log in to answer this question.

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