Getting a PID from a Background Process Run as Another User
Asked Answered
B

5

6

Getting a background process ID is easy to do from the prompt by going:

$ my_daemon &
$ echo $!

But what if I want to run it as a different user like:

su - joe -c "/path/to/my_daemon &;"

Now how can I capture the PID of my_daemon?

Bauhaus answered 1/6, 2011 at 6:33 Comment(1)
This looks solidly on-topic for SO to me; it is a question about shell programming, and as such is within the remit of SO.Calcic
C
13

Succinctly - with a good deal of difficulty.

You have to arrange for the su'd shell to write the child PID to a file and then pick the output. Given that it will be 'joe' creating the file and not 'dex', that adds another layer of complexity.

The simplest solution is probably:

su - joe -c "/path/to/my_daemon & echo \$! > /tmp/su.joe.$$"
bg=$(</tmp/su.joe.$$)
rm -f /tmp/su.joe.$$   # Probably fails - joe owns it, dex does not

The next solution involves using a spare file descriptor - number 3.

su - joe -c "/path/to/my_daemon 3>&- & echo \$! 1>&3" 3>/tmp/su.joe.$$
bg=$(</tmp/su.joe.$$)
rm -f /tmp/su.joe.$$

If you're worried about interrupts etc (and you probably should be), then you trap things too:

tmp=/tmp/su.joe.$$
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
su - joe -c "/path/to/my_daemon 3>&- & echo \$! 1>&3" 3>$tmp
bg=$(<$tmp)
rm -f $tmp
trap 0 1 2 3 13 15

(The caught signals are HUP, INT, QUIT, PIPE and TERM - plus 0 for shell exit.)

Warning: nice theory - untested code...

Calcic answered 1/6, 2011 at 6:51 Comment(2)
Awesome answer. I might be able to get by with just this: su - joe -c "/path/to/my_daemon & echo \$! > /tmp/su.joe.$$" escaping the $! and no semi-colon after the my_daemon & are certainly gotchas too. I'm going to play around with it a little bit.Bauhaus
Be sure to add a space after the $! or the shell may interpret this weirdly.Fleda
B
1

The approaches presented here didn't work for me. Here's what I did:

PID_FILE=/tmp/service_pid_file
su -m $SERVICE_USER -s /bin/bash -c "/path/to/executable $ARGS >/dev/null 2>&1 & echo \$! >$PID_FILE"
PID=`cat $PID_FILE`
Bellhop answered 5/2, 2016 at 20:31 Comment(0)
C
1

As long as the output from the background process is redirected, you can send the PID to stdout:

su "${user}" -c "${executable} > '${log_file}' 2>&1 & echo \$!"

The PID can then be redirected to a file owned by the first user, rather than the second user.

su "${user}" -c "${executable} > '${log_file}' 2>&1 & echo \$!" > "${pid_file}"

The log files do need to be owned by the second user to do it this way, though.

Clo answered 10/9, 2020 at 18:54 Comment(0)
M
-1

Here's my solution

su oracle -c "/home/oracle/database/runInstaller" &
pid=$(pgrep -P $!)

Explantation

  • pgrep -P $! - Gets the child process of the parent pid $!
Mathia answered 11/1, 2013 at 7:16 Comment(1)
Why is this downvoted? Two lines of succinct code without use of tmp files.Mathia
R
-1

I took the above solution by Linux, but had to add a sleep to give the child process a chance to start.

su - joe -c "/path/to/my_daemon > /some/output/file" &
parent=$!
sleep 1
pid=$(pgrep -P $parent)

Running in bash, it doesn't like pid=$(pgrep -P $!) but if I add a space after the ! it's ok: pid=$(pgrep -P $! ). I stuck with the extra $parent variable to remind myself what I'm doing next time I look at the script.

Rittenhouse answered 12/4, 2013 at 18:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.