Bash: start remote python application through ssh and get its PID
Thanks to Kingslndian i solved it by making one single command that did the three steps i required, so with that avoided the problem of running in different shells:
ssh root@myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 & echo $! > "dmr.pid"'
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.
Bash: Using SSH to start a long-running remote command and collect its PID
Try this instead:
read -r pid \
< <(ssh 10.10.10.46 'nohup mbuffer >/tmp/mtest </dev/null 2>/tmp/mtest.err & echo $!')
Three important changes:
- Use of
nohup
(you could also get a similar effect with the bash built-indisown
) - Redirection of stdin and stderr to files (preventing them from holding handles that connect, eventually, to your terminal).
- Use of single quotes for the remote command (with double-quotes, expansions happen before
ssh
is started, so the$!
you get is the PID of the most recently started local background process).
Get PID of a remote process started with sshpass
sshpass -p password ssh user@ipaddr /bin/bash << EOF
nohup process > /dev/null 2>&1 & echo $! > pid_file
cat pid_file
EOF
The thing is that $!
get's expanded not on the remote computer, but on your computer. When using the Here document, variable names are replaced by their values. So it gets expanded to whatever process you have had run in the background on you computer. You need to execute echo $!
on the remote computer. That's why it's good to use -c
and to always properly enclose the arguments.
sshpass -p password ssh user@ipaddr /bin/bash -c 'nohup process >/dev/null 2>&1 & echo $! > pid_file'
or you can just escape the $!
:
sshpass -p password ssh user@ipaddr /bin/bash <<EOF
nohup process > /dev/null 2>&1 & echo \$! > pid_file
cat pid_file
EOF
or the best is to use quoted here string delimiter:
sshpass -p password ssh user@ipaddr /bin/bash <<'EOF'
nohup process > /dev/null 2>&1 & echo $! > pid_file
cat pid_file
EOF
ssh run script in background and get its pid
ssh some.host './script & echo $!'
how can i ssh into a server, and read a pid file and bring back the #?
Easiest way is with backticks.
my $output = `ssh server -l myid -i /home/myid/.ssh/authorized_keys some_command`;
$output
will contain the output of your ssh
command.
How to run a script in the background even after I logout SSH?
Run nohup python bgservice.py &
to get the script to ignore the hangup signal and keep running. Output will be put in nohup.out
.
Ideally, you'd run your script with something like supervise
so that it can be restarted if (when) it dies.
Conditionally run subprocess over ssh, while appending output to a (potentially remote) file
You're not going to get something that's safe and correct in a one-liner without making it unreadable; better not to try.
Note that we're using a shell here: In the local case we explicitly call shell=True
, whereas in the remote case ssh
always, implicitly starts a shell.
import shlex
import subprocess
def startBackgroundCommand(argv, outputFile, remoteHost=None, andGetPID=False):
cmd_str = ' '.join(shlex.quote(word) for word in argv)
if outputFile != None:
cmd_str += ' >%s' % (shlex.quote(outputFile),)
if andGetPID:
cmd_str += ' & echo "$!"'
if remoteHost != None:
p = subprocess.Popen(['ssh', remoteHost, cmd_str], stdout=subprocess.PIPE)
else:
p = subprocess.Popen(cmd_str, stdout=subprocess.PIPE, shell=True)
return p.communicate()[0]
# Run your command locally
startBackgroundCommand(['python', 'script.py', 'arg_1'],
outputFile='file.log', andGetPID=True)
# Or run your command remotely
startBackgroundCommand(['python', 'script.py', 'arg_1'],
remoteHost='foo.example.com', outputFile='file.log', andGetPID=True)
Related Topics
Are Debug Symbols Loaded into Memory on Linux
Tail Logback Log Files with Log Level Coloring in Linux Server
How to Delete 5 Lines Before and 6 Lines After Pattern Match Using Sed
Program Life in Terms of Paged Segmentation Memory
How to Enable Mixed Mode Debugging in Visual Studio Code
How Does Linux Kernel Prevents The Bios System Calls
Udev Rules Are Not Working for Libusb on Ubuntu 12.04
Example of Using External Libraries or Packages in Common Lisp
Nasm X86_64 Assembly in 32-Bit Mode: Why Does This Instruction Produce Rip-Relative Addressing Code
How to Lock The Cursor to The Inside of a Window on Linux
Synchronize Shell Script Execution
Using Winscp to Grab a File Through a Tunnel
Detecting If The Monitor Is Powered Off