How to run nohup and write its pid file in a single bash statement - linux

I want to run my script in background and then write its pid file. I am using nohup to do this.
This is what i came up with,
nohup ./myprogram.sh > /dev/null 2>&1 & && echo $! > run.pid
But this gives a syntax error.
The following doesn't give syntax error but the problem is echo $! doesn't write the correct pid since nohup is run in a sub shell
(nohup ./myprogram.sh > /dev/null 2>&1 &) && echo $! > run.pid
Any solutions for this, given i want a single line statement for achieving this?

You already have one ampersand after the redirect which puts your script in background. Therefore you only need to type the desired command after that ampersand, not prefixed by anything else:
nohup ./myprogram.sh > /dev/null 2>&1 & echo $! > run.pid

This should work:
nohup ./myprogram.sh > /dev/null 2>&1 &
echo $! > run.pid

Grigor's answer is correct, but not complete.
Getting the pid directly from the nohup command is not the same as getting the pid of your own process.
running ps -ef:
root 31885 27974 0 12:36 pts/2 00:00:00 sudo nohup ./myprogram.sh
root 31886 31885 25 12:36 pts/2 00:01:39 /path/to/myprogram.sh
To get the pid of your own process, you can use:
nohup ./myprogram.sh > /dev/null 2>&1 & echo $! > run.pid
# allow for a moment to pass
cat run.pid | pgrep -P $!
Note that if you try to run the second command immediately after nohup, the child process will not exist yet.

Related

How to kill a process by reading from pid file using bash script in Jenkins?

Inside Jenkins, I have to run 2 separate scripts: start.sh and stop.sh. These scripts are inside my application which is fetched from a SCM . They are inside same directory.
The start.sh script runs a process in the background using nohup, and writes the processId to save_pid.pid. This script works fine. It successfully starts my application.
Then inside stop.sh, I am trying to read the processId from save_pid.pid to delete the process. But,I am unable to delete the process and the application keeps running until I kill the process manually using: sudo kill {processId}.
Here are the approaches that I have tried so far inside stop.sh but none of these work:
kill $(cat /path/to/save_pid.pid)
kill `cat /path/to/save_pid.pid`
kill -9 $(cat /path/to/save_pid.pid)
kill -9 `cat /path/to/save_pid.pid`
pkill -F /path/to/save_pid.pid
I have also tried all of these steps with sudo as well. But, it just doesn't work. I have kept an echo statement inside stop.sh, which prints and then there is nothing.
What am I doing wrong here ?
UPDATE:
The nohup command that I am using inside start.sh is something like this:
nohup deploy_script > $WORKSPACE/app.log 2>&1 & echo $! > $WORKSPACE/save_pid.pid
Please Note:
In my case, the value written inside save_pid.pid is surprisingly
always less by 1 than the value of actual processId. !!!
I think the reason why this happens is because you are not getting the PID of the process that you are interested in, but the PID of the shell executing your command.
Look:
$ echo "/bin/sleep 10" > /tmp/foo
$ chmod +x /tmp/foo
$ nohup /tmp/foo & echo $!
[1] 26787
26787
nohup: ignoring input and appending output to 'nohup.out'
$ pgrep sleep
26789
So 'nohup' will exec the 'shell', the 'shell' will fork a second 'shell' to exec 'sleep' in, however I can only count two processes here, so I am unable to account for one created PID.
Note that, if you put the nohup and the pgrep on one line, then pgrep will apparently be started faster than the shell that 'exec's 'sleep' and thus pgrep will yield nothing, which somewhat confirms my theory:
$ nohup /tmp/foo & echo $! ; pgrep sleep
[2] 26899
nohup: ignoring input and appending output to 'nohup.out'
$
If you launch your process directly, then nohup will "exec" your process and thus keep the same PID for the process as nohup itself had (see http://sources.debian.net/src/coreutils/8.23-4/src/nohup.c/#L225):
$ nohup /bin/sleep 10 & echo "$!"; pgrep sleep
[1] 27130
27130
nohup: ignoring input and appending output to 'nohup.out'
27130
Also, if you 'exec' 'sleep' inside the script, then there's only one process that's created (as expected):
$ echo "exec /bin/sleep 10" > /tmp/foo
$ nohup /tmp/foo & echo "$!"; pgrep sleep
[1] 27309
27309
nohup: ignoring input and appending output to 'nohup.out'
27309
Thus, according to my theory, if you'd 'exec' your process inside the script, then you'd be getting the correct PID.

Propagate exit code from runuser command

I want to run the bash script, StartSomething.sh, as a specific user. I use runuser command for that. Also I want to know an exit code from this bash script. So I write an exit code to the file when the command is finished or interrupted. Here is the code:
runuser myuser -s /bin/bash -c "./StartSomething.sh --pidfile=${pidfile}; \
echo $? > ${statusfile};" &
sleep 5
pid=$(cat ${pidfile})
while ps -p ${pid} > /dev/null; do sleep 1; done
end=$(cat ${statusfile})
echo "End code: ${end}"
exit ${end}
Problem is that exit code is still 0, though bash script is interrupted. What can be wrong?
If I have separate file, start.sh, with this code:
./StartSomething.sh --pidfile=${pidfile}
echo $? > ${statusfile}
and runuser command look like this:
runuser myuser -s /bin/bash -c "./start.sh" &
everything is working fine. I want to use first example without separate file. Can someone tell me what can be wrong? Is there better solution for this problem?
If all you want to do is to run the program in the background, and wait for it to finish, I think you could also use wait to get the return value (runuser passes it through, unless something exceptional happens):
runuser myuser ./StartSomething.sh --pidfile=${pidfile} &
pid=$!
# do something else
wait $!
echo "it returned $?"
or
runuser myuser ./StartSomething.sh --pidfile=${pidfile} &
pid=$!
echo -n "waiting"
while kill -0 $pid 2>/dev/null; do
echo -n "."
sleep 1
done
echo
wait $!
echo "it returned $?"
There is problem with escaping special character $. Correct command:
runuser myuser -s /bin/bash -c "./StartSomething.sh --pidfile=${pidfile}; \
echo \$? > ${statusfile};" &
Replace $? with \$?.

why nohup does not launch my script?

Here is my script.sh
for ((i=1; i<=400000; i++))
do
echo "loop $i"
echo
numberps=`ps -ef | grep php | wc -l`;
echo $numberps
if [ $numberps -lt 110 ]
then
php5 script.php &
sleep 0.25
else
echo too much process
sleep 0.5
fi
done
When I launch it with:
./script.sh > /dev/null 2>/dev/null &
that works except when I logout from SSH and login again, I cannot stop the script with kill%1 and jobs -l is empty
When I try to launch it with
nohup ./script.sh &
It just ouputs
nohup: ignoring input and appending output to `nohup.out'
but no php5 are running: nohup has no effect at all
I have 2 aleternatives to solve my problem:
1) ./script.sh > /dev/null 2>/dev/null &
If I logout from SSH and login again, How can I delete this job ?
or
2) How to make nohup run correctly ?
Any idea ?
nohup is not supposed to allow you to use jobs -l or kill %1 to kill jobs after logging out and in again.
Instead, you can
Run the script in the foreground in a GNU Screen or tmux session, which lets you log out, log in, reattach and continue the same session.
killall script.sh to kill all running instances of script.sh running on the server.

Get the pid of a command whose output is piped

In order to remotely start a program, log its output and immediately see that log, I'm using this script:
nohup mycommand 2>&1 | tee -a server.log &
Now, I would like to store in a file the pid of the newly started mycommand (whose name is very generic, I can't just use pgrep as there would be a risk of collision).
If I just add echo $! > mycommand.pid I get the pid of tee.
How can I reliably write the pid of mycommand to a file ?
And by the way, why doesn't this give the right pid ?
( nohup mycommand 2>&1 ; echo $! > mycommand.pid ) | tee -a server.log &
OK, this simple variant works :
( nohup mycommand 2>&1 & echo $! > mycommand.pid ) | tee -a server.log &
I'm not sure why the ; didn't work and why I have to use & instead.

How do run commands in background one by one?

nohup php /home/www/api/24 > 24.out 2> 24.err < /dev/null
nohup php /home/www/api/27 > 27.out 2> 27.err < /dev/null
nohup php /home/www/api/19 > 27.out 2> 16.err < /dev/null
I have a few thousand api calls I need to make and need to be done one by one so I don't flood the other server with web calls. After I run the sh file, how can I close the terminal without interrupting the process, CTRL+Z ?
You type...
$ screen
...and hit enter.
Run the command or script.
Press control-a, then d
Then you can disconnect, log out, do whatever... come back later and check on the script:
$ screen -r
Then you wonder how you ever got along without it.
https://www.gnu.org/software/screen/
Put everything in a script, and then run that script with nohup:
#!/bin/bash
for i in 24 27 19 ...
do
php /home/www/api/$i > $i.out 2> $i.err
done
Then do:
nohup /path/to/script </dev/null >/dev/null 2>&1 &
You could also use the batch(1) command with a here document, e.g:
batch << EOJ
php /home/www/api/24 > 24.out 2> 24.err < /dev/null
php /home/www/api/17 > 17.out 2> 17.err < /dev/null
php /home/www/api/19 > 19.out 2> 19.err < /dev/null
EOJ

Resources