I want to start process (eg. myCommand) and get its pid (to allow to kill it later).
I tried ps and filter by name, but I can not distinguish process by names
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Because processes names are not unique.
I can run process by:
myCommand &
I found that I can get this PID by:
echo $!
Is there any simpler solution?
I would be happy to execute myCommand and get its PID as a result of one line command.
What can be simpler than
echo $!
? As one line:You can use
sh -c
andexec
to get the command's PID even before it runs.To start
myCommand
, so that its PID is printed before it begins to run, you can use:How it works:
This starts a new shell, prints the PID of that shell, and then uses the
exec
builtin to replace the shell with your command, ensuring it has the same PID. When your shell runs a command with theexec
builtin, your shell is actually becoming that command, rather than the more common behavior of forking a new copy of itself, which has its own separate PID and which then becomes the command.I find this to be much simpler than alternatives involving asynchronous execution (with
&
), job control, or searching withps
. Those approaches are fine, but unless you have a specific reason to use them--for example, perhaps the command is already running, in which case searching for its PID or using job control would make sense--I suggest considering this way first. (And I would certainly not consider writing a complex script or other program to achieve this).This answer includes an example of this technique.
Parts of that command could occasionally be omitted, but not usually.
Even if the shell you're using is a Bourne-style and thus supports the
exec
builtin with these semantics, you generally shouldn't try to avoid usingsh -c
(or equivalent) to create a new, separate shell process for this purpose, because:myCommand
, there's no shell waiting to run subsequent commands.sh -c 'echo $$; exec myCommand; foo
would not be able to attempt to runfoo
after replacing itself withmyCommand
. Unless you're writing a script that runs this as its last command, you can't just useecho $$; exec myCommand
in a shell where you are running other commands.(echo $$; exec myCommand)
may be syntactically nicer thansh -c 'echo $$; exec myCommand'
, but when you run$$
inside(
)
, it gives the PID of the parent shell, not of the subshell itself. But it is the subshell's PID that will be the PID of the new command. Some shells provide their own non-portable mechanisms for finding the subshell's PID, which you could use for this. In particular, in Bash 4,(echo $BASHPID; exec myCommand)
does work.Finally, note that some shells will perform an optimization where they run a command as if by
exec
(i.e., they forgo forking first) when it is known that the shell will not need to do anything afterward. Some shells try to do this anytime it is the last command to be run, while others will only do it when there are no other commands before or after the command, and others will not do it at all. The effect is that if your forget to writeexec
and just usesh -c 'echo $$; myCommand'
then it will sometimes give you the right PID on some systems with some shells. I recommend against ever relying on such behavior, and instead always includingexec
when that's what you need.Wrap the command in a small script
I do not know of any simpler solution, but isn't using $! good enough? You can always assign the value to some other variable if you need it later, as said by others.
As a side note, instead of piping from ps you could use
pgrep
orpidof
.use exec from a bash script after registering the pid to a file:
example:
suppose you have a script named "forever.sh" that you want to run with args p1,p2,p3
forever.sh sourcecode:
create a reaper.sh:
run forever.sh through reaper.sh:
forever.sh does nothing more than logging a line to syslog each 5 seconds
you now have the pid in /var/run/forever.sh.pid
and forever.sh is running aok. syslog grep:
you can see it in the process table:
In the bash shell an alternative to
$!
might be thejobs -p
built-in. In some cases the!
in$!
gets interpreted by the shell before (or instead of) the variable expansion, leading to unexpected results.This, for example, won't work:
while this will:
You can use something like:
Or
The two commands can be joints using
;
or&&
. In the second case, the pid will be set only if the first command succeeds. You can get the process id from$pid
.This is a bit of a hack-y answer and won't likely work for most people. It's also a huge security risk methinks, so don't do it unless you're sure you'll be safe and the inputs are sanitized and...well, you get the idea.
Compile the little C program here into a binary called
start
(or whatever you want), then run your program as./start your-program-here arg0 arg1 arg2 ...
Long story short, this will print the PID to
stdout
, then load your program into the process. It should still have the same PID.