336

I want to have a shell script like this:

my-app &
echo $my-app-pid

But I do not know how the get the pid of the just executed command.

I know I can just use the jobs -p my-app command to grep the pid. But if I want to execute the shell multiple times, this method will not work. Because the jobspec is ambiguous.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
David S.
  • 5,529
  • 5
  • 30
  • 39

4 Answers4

440

The PID of the last executed command is in the $! shell variable:

my-app &
echo $!
brandizzi
  • 2,814
  • 3
  • 21
  • 29
enzotib
  • 50,671
  • 14
  • 120
  • 105
  • 1
    It is printing pid as for eg. [1] 893 . I want only number. – user3153014 Sep 04 '14 at 11:47
  • 49
    It should be noted that this stands for programs started *in the background*. If no background processes have been started the parameter is not set. – ramrunner Nov 17 '14 at 21:52
  • 7
    Another worthy solution is suggested in (a comment to an answer to) [How to get pid of just started process](http://serverfault.com/a/205563/68972): oh, and the "oneliner": `/bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &` – sysfault Nov 24 '10 at 14:28 – imz -- Ivan Zakharyaschev Jun 02 '15 at 14:11
  • 17
    @user3153014 String s like "[2] 2625" are printed by shell after starting background task. This is not related to output of `echo $!` – Petr Gladkikh Jul 26 '15 at 05:21
  • I usually use such code in a script when I need to wait until the process ends. `my-app & myVar=$! ; fg`. `fg` brings the process to foreground again. I can then print `echo $myVar` later and I'm pretty sure that the my-app has already finished. – Vrata Blazek Mar 04 '19 at 17:17
  • If you are using that inside `su {user} -c {command}` as `command`, be sure to escape the `$!` (use `\$!`). See https://unix.stackexchange.com/questions/147916/getting-the-process-id-out-of-command-launched-with-su-c – Michele Piccolini Feb 28 '20 at 12:42
  • @VrataBlazek `fg: no job control` – Michael Apr 16 '20 at 00:09
  • @imz--IvanZakharyaschev Why is it necessary to pipe the PID to a file? If I try to wrap the shell call with $() it hangs at that point... why can't I get it into a shell variable directly? When I try to pipe it to a file I have another problem - now the PID of my command isn't the same as reported, whereas if I don't pipe it's the same! – Michael Apr 16 '20 at 00:25
  • @Michael Hiw do you want to get it into a shell variable directly? If you suggest a method, I could try to say whether it would work or not. As for `$()` wrapping, I can't try to explain the behavior without seeing the exact code. – imz -- Ivan Zakharyaschev Apr 18 '20 at 11:14
87

Get PID:

#!/bin/bash
my-app &
echo $!

Save PID in variable:

#!/bin/bash
my-app &
export APP_PID=$!

Save all instances PID in text file:

#!/bin/bash
my-app &
echo $! >>/tmp/my-app.pid

Save output, errors and PID in separated files:

#!/bin/bash
my-app >/tmp/my-app.log 2>/tmp/my-app.error.log &
echo $! >>/tmp/my-app.pid

echo "my-app PID's: $(cat /tmp/my-app.pid)"
Eduardo Cuomo
  • 1,220
  • 10
  • 10
  • 3
    The question didn't ask about redirection, then your answer is the mostly the same as the accepted one except that if an instance of `my-app` finishes, and perhaps even worse its PID gets reused later, you'll have bad information in your file. I don't think this answer adds much of value to the existing accepted answer really – Eric Renouf Jan 22 '16 at 15:12
  • 1
    @EricRenouf post updated! – Eduardo Cuomo Jan 22 '16 at 15:42
  • another derivative that might be useful. This gets the PID and at the same time treats it as a (mostly) foreground process: `sleep 4 | grep INVALID & export MY_PID=$!; fg; echo $MY_PID returned with $?` ` – mlathe Apr 26 '18 at 21:53
  • isnt APP=`main &` a way to grab PID? – MrMesees Aug 30 '18 at 07:54
3

Try something like

pidof my_app >> /tmp/my_app.pid
Piyush Jain
  • 348
  • 1
  • 6
  • 2
    external command, and slow, if system can give PID directly why searching through all processes to find just that? and also, can't be certain you'll get correct value – papo Jan 02 '19 at 08:13
-5

Try something like this:

 ps ef | grep "[m]y-app" | awk '{print $2}'

Placing the first letter of your process between [ ] makes sure you do not get the grep process in your list. If needed you can also add a grep on your username.

Eduardo Cuomo
  • 1,220
  • 10
  • 10
Goez
  • 1,568
  • 1
  • 10
  • 6
  • 11
    That's very fragile at best and doesn't work if `my-app` is executed more than once - **davidshen84** specifically worries about that cas. – Mat Jan 30 '12 at 12:10
  • 4
    If you even go this route, you should use ```pgrep``` instead. – Willem Jan 19 '15 at 12:41