How to run nohup and write its pid file in a single bash statement
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
Get PID of nohup process through ssh
Don't use (command &) &
. Just use (command) &
(or just command &
). With (command &) &
, Bash needs to fork another sub-shell to run the command so $!
would be the PID of the sub-shell other than the command.
See following example:
[STEP 124] # (nohup sleep 1234 > /dev/null 2>&1 &) &
[1] 44420 <=== this is the PID of the sub-shell which died immediately
[STEP 125] #
[1]+ Done ( nohup sleep 1234 > /dev/null 2>&1 & )
[STEP 126] # ps p 44420 <=== as you can see this PID does not exist any more
PID TTY STAT TIME COMMAND
[STEP 127] # ps -C sleep u
USER PID TTY STAT START TIME COMMAND
root 44421 pts/13 S 17:48 0:00 sleep 1234
[STEP 128] # kill 44421
[STEP 129] #
This would work fine:
[STEP 131] # (nohup sleep 1234 > /dev/null 2>&1) &
[1] 44424 <=== this is the PID of the sleep command
[STEP 132] # ps p 44424 u
USER PID TTY STAT START TIME COMMAND
root 44424 pts/13 S 17:49 0:00 sleep 1234
[STEP 133] #
How to get the process ID to kill a nohup process?
When using nohup
and you put the task in the background, the background operator (&
) will give you the PID at the command prompt. If your plan is to manually manage the process, you can save that PID and use it later to kill the process if needed, via kill PID
or kill -9 PID
(if you need to force kill). Alternatively, you can find the PID later on by ps -ef | grep "command name"
and locate the PID from there. Note that nohup
keyword/command itself does not appear in the ps
output for the command in question.
If you use a script, you could do something like this in the script:
nohup my_command > my.log 2>&1 &
echo $! > save_pid.txt
This will run my_command
saving all output into my.log
(in a script, $!
represents the PID of the last process executed). The 2
is the file descriptor for standard error (stderr
) and 2>&1
tells the shell to route standard error output to the standard output (file descriptor 1
). It requires &1
so that the shell knows it's a file descriptor in that context instead of just a file named 1
. The 2>&1
is needed to capture any error messages that normally are written to standard error into our my.log
file (which is coming from standard output). See I/O Redirection for more details on handling I/O redirection with the shell.
If the command sends output on a regular basis, you can check the output occasionally with tail my.log
, or if you want to follow it "live" you can use tail -f my.log
. Finally, if you need to kill the process, you can do it via:
kill -9 `cat save_pid.txt`
rm save_pid.txt
How do I use the nohup command without getting nohup.out?
The nohup
command only writes to nohup.out
if the output would otherwise go to the terminal. If you have redirected the output of the command somewhere else - including /dev/null
- that's where it goes instead.
nohup command >/dev/null 2>&1 # doesn't create nohup.out
Note that the >/dev/null 2>&1
sequence can be abbreviated to just >&/dev/null
in most (but not all) shells.
If you're using nohup
, that probably means you want to run the command in the background by putting another &
on the end of the whole thing:
nohup command >/dev/null 2>&1 & # runs in background, still doesn't create nohup.out
On Linux, running a job with nohup
automatically closes its input as well. On other systems, notably BSD and macOS, that is not the case, so when running in the background, you might want to close input manually. While closing input has no effect on the creation or not of nohup.out
, it avoids another problem: if a background process tries to read anything from standard input, it will pause, waiting for you to bring it back to the foreground and type something. So the extra-safe version looks like this:
nohup command </dev/null >/dev/null 2>&1 & # completely detached from terminal
Note, however, that this does not prevent the command from accessing the terminal directly, nor does it remove it from your shell's process group. If you want to do the latter, and you are running bash, ksh, or zsh, you can do so by running disown
with no argument as the next command. That will mean the background process is no longer associated with a shell "job" and will not have any signals forwarded to it from the shell. (A disown
ed process gets no signals forwarded to it automatically by its parent shell - but without nohup
, it will still receive a HUP
signal sent via other means, such as a manual kill
command. A nohup
'ed process ignores any and all HUP
signals, no matter how they are sent.)
Explanation:
In Unixy systems, every source of input or target of output has a number associated with it called a "file descriptor", or "fd" for short. Every running program ("process") has its own set of these, and when a new process starts up it has three of them already open: "standard input", which is fd 0, is open for the process to read from, while "standard output" (fd 1) and "standard error" (fd 2) are open for it to write to. If you just run a command in a terminal window, then by default, anything you type goes to its standard input, while both its standard output and standard error get sent to that window.
But you can ask the shell to change where any or all of those file descriptors point before launching the command; that's what the redirection (<
, <<
, >
, >>
) and pipe (|
) operators do.
The pipe is the simplest of these... command1 | command2
arranges for the standard output of command1
to feed directly into the standard input of command2
. This is a very handy arrangement that has led to a particular design pattern in UNIX tools (and explains the existence of standard error, which allows a program to send messages to the user even though its output is going into the next program in the pipeline). But you can only pipe standard output to standard input; you can't send any other file descriptors to a pipe without some juggling.
The redirection operators are friendlier in that they let you specify which file descriptor to redirect. So 0<infile
reads standard input from the file named infile
, while 2>>logfile
appends standard error to the end of the file named logfile
. If you don't specify a number, then input redirection defaults to fd 0 (<
is the same as 0<
), while output redirection defaults to fd 1 (>
is the same as 1>
).
Also, you can combine file descriptors together: 2>&1
means "send standard error wherever standard output is going". That means that you get a single stream of output that includes both standard out and standard error intermixed with no way to separate them anymore, but it also means that you can include standard error in a pipe.
So the sequence >/dev/null 2>&1
means "send standard output to /dev/null
" (which is a special device that just throws away whatever you write to it) "and then send standard error to wherever standard output is going" (which we just made sure was /dev/null
). Basically, "throw away whatever this command writes to either file descriptor".
When nohup
detects that neither its standard error nor output is attached to a terminal, it doesn't bother to create nohup.out
, but assumes that the output is already redirected where the user wants it to go.
The /dev/null
device works for input, too; if you run a command with </dev/null
, then any attempt by that command to read from standard input will instantly encounter end-of-file. Note that the merge syntax won't have the same effect here; it only works to point a file descriptor to another one that's open in the same direction (input or output). The shell will let you do >/dev/null <&1
, but that winds up creating a process with an input file descriptor open on an output stream, so instead of just hitting end-of-file, any read attempt will trigger a fatal "invalid file descriptor" error.
Get the pid and return status from nohup + sudo
My final solutions:
#!/usr/bin/env bash
ROOT=$(cd `dirname $0`; pwd)
sudo kill -9 `cat ${ROOT}/pids` || true
nohup sudo node server.js >> node.log 2>&1 &
sleep 1
pid=$(ps --ppid $! | tail -1 | awk '{ print $1 }')
if echo $pid | egrep -q '^[0-9]+$'; then
echo $pid > ${ROOT}/pids
else
echo 'server not started!'
fi
Execute a script through ssh and store its pid in a file on the remote machine
Use
ssh user@remote_machine 'nohup ./script.sh > /dev/null 2>&1 & echo $! > ./pid.log'
OR
ssh user@remote_machine "nohup ./script.sh > /dev/null 2>&1 & echo \$! > ./pid.log"
Issue:
Your $!
was getting expanded locally, before calling ssh at all.
Worse, before calling the ssh command, if there was a process stared in the background, then $!
would have expanded to that and complete ssh command would have got expanded to contain that PID as argument to echo.
e.g.
$ ls &
[12342] <~~~~ This is the PID of ls
$ <~~~~ Prompt returns immediately because ls was stared in background.
myfile1 myfile2 <~~~~ Output of ls.
[1]+ Done ls
#### At this point, $! contains 12342
$ ssh user@remote "command & echo $! > pidfile"
# before even calling ssh, shell internally expands it to:
$ ssh user@remote "command & echo 12342 > pidfile"
And it will put the wrong PID in the pidfile.
Get PID of the jobs submitted by nohup in Linux
ps
give the status of local processes. bsub
can be used to get the status of processes on each remote machine.
How do I put an already-running process under nohup?
Using the Job Control of bash to send the process into the background:
- Ctrl+Z to stop (pause) the program and get back to the shell.
bg
to run it in the background.disown -h [job-spec]
where [job-spec] is the job number (like%1
for the first running job; find about your number with thejobs
command) so that the job isn't killed when the terminal closes.
how to save PID when executing multiple shell script from one shell script?
Try $!
right after you issue the nohup
. It should return the child-pid. It will be overwritten every time you fork a child process.
Alternatively, you could save $$
from the child process (e.g. First.sh, Second.sh ...)
nohup sh First.sh &
FIRST_PID=$!
nohup sh Second.sh &
SECOND_PID=$!
nohup sh Third.sh &
THIRD_PID=$!
Related Topics
Why Does the Linux Kernel Repository Have Only One Branch
What Is the Reason and How to Avoid the [Fin, Ack] , [Rst] and [Rst, Ack]
How to Monitor Data on a Serial Port in Linux
Linux Distribution Binary Compatibility
Building Linux Kernel on MAC Os X
In a Linux Shell How to Process Each Line of a Multiline String
How to Automatically Pipe to Less If the Result Is More Than a Page on My Shell
Storing & Accessing Up to 10 Million Files in Linux
Tool to Visualize the Device Tree File (Dtb) Used by the Linux Kernel
How to Write Non-Ascii Characters Using Echo
Stracing to Attach to a Multi-Threaded Process
Linux: Screen Desktop Video Capture Over Network, and Vnc Framerate
"Git Add" Returning "Fatal: Outside Repository" Error
Git Aliases - Command Line Autocompletion of Branch Names
How to Fetch Java Version Using Single Line Command in Linux