Getting PID value over SSH, doesn't work until exit - linux

I would like to start mbuffer in listening mode on a remote server, so I do
ssh -f root#10.10.10.46 'mbuffer -4 -v 0 -q -I 8023 > /tmp/mtest & echo $!'
and it outputs the PID number, which I would like to save in $pidValue, but if I do
pidValue=$(ssh -f 10....)
then it doesn't exit until the mbuffer process exits.
Question
How do I get the PID value from the mbuffer process?

before running the process which uses the remote PID, scp the remote file to local storage, from where you deal with it as you like.
it seems that this construct:
read -r var < <(ssh remote "echo test; sleep 5") ; echo $var
can give you results earlier, but that may depend on the remote process you're starting. Try that.

Related

How to assign to a bash variable an ssh remote command the pid while capturing its

Introduction
My question is very similar to this one, except that I'd like the output from the command to be redirected to a local file instead of a remote one.
The questioner was asking for a way to retrieve the process ID with a command similar to this one, where the mbuffer command wouldn't cause hanging:
read -r pid < <(ssh 10.10.10.46 "mbuffer -4 -v 0 -q -I 8023 > /tmp/mtest & echo $!"); echo $pid
The answerer responded with the following command to resolve the problem
read -r pid \
< <(ssh 10.10.10.46 'nohup mbuffer >/tmp/mtest </dev/null 2>/tmp/mtest.err & echo $!')
Which is really helpful but still places files on the remote machine, not the local one.
My Attempts
The following is my attempt to capture a log of the output of $command:
read -r PID < <(ssh $remote 'nohup $command >&2 & echo $!' 2> $log)
Which sets PID to the process ID properly but doesn't produce a log.
Question
How can I capture a log on my local machine of the stdout of my $command while still assigning PID to the process ID of $command?
Another approach:
{ read -r pid;
# Do whatever you want with $pid of the process on remote machine
cat > my_local_system_log_file
} <(ssh 10.10.10.46 "mkfifo /tmp/mtest; mbuffer -4 -v 0 -q -I 8023 &> /tmp/mtest & echo $!; cat /tmp/mtest");
Basically, the first line is PID & further lines are logs from the process.

Bash: Using SSH to start a long-running remote command and collect its PID

When I do the following, then I have to press CTRL-c afterwards or the shell acts weird. Left/right arrows keys e.g. doesn't move correctly and the text is messed up.
# read -r pid < <(ssh 10.10.10.46 'sleep 50 & echo $!') ; echo $pid
2135
# Killed by signal 2.
^C
#
I need this for a script, so I'd like to know why CTRL-c is needed and is it possible to work around it?
Update
It looks like it opens an extra Bash shell, and that is the one that needs to be exited.
The command I am actually interesting in is
read -r pid < <(ssh 10.10.10.46 "mbuffer -4 -v 0 -q -I 8023 > /tmp/mtest & echo $!"); echo $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-in disown)
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).

Bash: start remote python application through ssh and get its PID

I'm creating a little bash script to copy new files from a windows machine to a remote linux centos server (i run this script using the git-shell) then i want to restart the python application thats running in the server to use those new files.
The problem is that everytime i run this script i want to end the actual running process before i start it again, so i want to get the pid of the process i start and save it to a file in the remote host so i can read it from there the next time i run the program and kill it.
My code by now looks similar to this:
echo "Copying code files to server..."
# The destination folder has to exist in the server
scp -r ./python/ root#myserver:/root/
echo "Checking for running processes..."
if ssh root#myserver 'ls dmr.pid >/dev/null'; then
echo "PID file exists, reading file..."
PID=$(ssh root#myserver 'cat dmr.pid')
# Terminate the actual process
echo "Terminating the process with PID '$PID'..."
ssh root#myserver 'kill $PID'
else
echo "PID file doesn't exist, not known processes running"
fi
# Restart the server and get the PID
echo "Restarting the server..."
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 &'
SERV_PID=$(ssh root#myserver 'echo $!')
echo "Saving PID to file dmr.pid"
ssh root#myserver "echo '$SERV_PID' > \"dmr.pid\""
echo "Sucesfully finished!"
The important lines are:
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 &'
SERV_PID=$(ssh root#myserver 'echo $!')
the problem with this is that the script finishes but the file ends up empty as well as the $SERV_PID variable.
And if i dont redirect the outputs and just do something like this:
SERV_PID=$(ssh root#myserver 'python /root/python/run_dev_server.py & echo $!')
i get stuck after "Restarting the server" and never get the PID or the file that will contain it or even the end of the script.
But if i run this right in the console:
ssh root#myserver 'python /root/python/run_dev_server.py & echo $!'
i get a PID printed to the terminal.
Any advice on this would be really appreciated.
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 &'
SERV_PID=$(ssh root#myserver 'echo $!')
With the above code, you are running two ssh commands and the both create two different shells. The problem is echo $! gives the most recent background process' ID from the current shell which is none.
That is, when you ssh for the second time, it's new shell and there's no background process running in it and hence echo $! gives no output. This explains why your PID file is empty.
Instead what you can do is to lookup for all instances of your python script and kill them using killall command. Or similar idea using ps command.
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"'

terminate infinite loop initiated in remote server when exiting bash script

Script which executes commands in infinite loop in background
<SOMETHING ELSE AT START OF SCRIPT>
cmd='while true;
do
ps aux | head;
sleep 1;
done > $FILE'
ssh root#$SERVER $cmd &
...
...
<SOME OTHER TASKS>
...
...
( at the end of this script, how to kill the above snippet executing in remote server)
[ kindly note i dont want to wait as the while loop is infinite ]
Read and tried some posts from stackoverflow, but could not find exact solution for this problem.
Rather than an infinite loop, use a sentinel file:
cmd='while [ -r /tmp/somefile];
do
# stuff
done > $FILE'
ssh root#$SERVER touch /tmp/somefile
ssh root#$SERVER $cmd &
# do other stuff
ssh root#$SERVER rm -f /tmp/somefile
This follows your current practice of putting the remote command in a variable, but the arguments against that cited elsewhere should be considered.
If you want to kill the ssh process running in background at the end of your script, just do:
kill $!
I assume this is the only (or the last) process you started in background.
Try following sequence
CTRL+Z
fg
CTRL+C
or
jobs
kill %jobspec
To kill everything belonging to user logged in you could try:
whois=`w|grep $user|awk '{print $2}'`;user=root; ssh $user#server -C "ps auwx|grep $whois|awk '{print \$2}'"
This will list all the processes owned by the user you just logged in as - just add |xargs kill -9
whois=`w|grep $user|awk '{print $2}'`;user=root; ssh $user#server -C "ps auwx|grep $whois|awk '{print \$2}'|xargs kill -9 "
whois=`w|grep $user|awk '{print $2}'`;user=root; ssh $user#server -C "ps auwx|grep $whois|awk '{print \$2}'|awk '{print "kill -9 " $1}'|/bin/sh "

Obtaining PID of Last Command Run on Other Machine

I am using the following code to launch a command on another machine:
#!/bin/bash
/usr/bin/rsh -n $Host_Name "cat asdf.txt &"
And I am trying to obtain the PID of the cat command by using the following:
/usr/bin/rsh -n $Host_Name pid="$!"
But when I echo $pid, it is just blank. What am I doing incorrectly? Is there an easier way of obtaining the PID of the last command that was executed on a different machine?
Thanks
You can only get the $! of the backgrounded command in the shell in which you started the command. If your command doesn't output anything to stderr, this could work:
/usr/bin/rsh -n $Host_Name "cat asdf.txt & echo $! >&2" 2> pidfile
The pid of the started command will then be stored locally in 'pidfile'.
Just a side-note: I would never use rsh. It is inherently insecure. I'd use ssh instead ;)

Resources