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

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.

Related

Working around sudo in shell script child process

So the reason I am asking this is because I'm running two programs simultaneously that are persistent, on the child process a programm is running that requires sudo rights.
#!/bin/bash
echo "Name the file:"
read filename
while [[ 1 -lt 2 ]]
do
if [ -f /home/max/dump/$filename.eth ]; then
echo "File already exist."
read filename
else
break
fi
done
#Now calling a new terminal for dumping
gnome-terminal --title="tcpdump" -e "sh /home/max/dump/dump.sh $filename.eth"
ping -c 1 0 > /dev/null **Waiting for tcpdump to create file**
#Packet analysis program is being executed
Script dump.sh
#!/bin/bash
filename=$1
echo password | sudo tcpdump -i 2 -s 60000 -w /home/max/dump/$filename -U
host 192.168.3.2
#Sudo still asks me for my password though password is piped into stdin

How to get PID from remote executed command?

If I do the following in Bash, then I get the PID of the remotely started mbuffer, and even though mbuffer is still running, I get the terminal back, which is what I want.
read -r pid < <(ssh 10.10.10.47 'nohup /opt/omni/bin/mbuffer -4 -s 128k -m 2G -v 0 -q -I 8023 >/tmp/mtest </dev/null 2>/tmp/mtest.err & echo $!')
echo $pid
Now I would like to do the same in Perl, so I try
use Capture::Tiny 'capture';
my ($stdout, $stderr, $exit) = capture {
system("read -r pid < <(ssh 10.10.10.47 'nohup /opt/omni/bin/mbuffer -4 -s 128k -m 2G -v 0 -q -I 8023 >/tmp/mtest </dev/null 2>/tmp/mtest.err & echo $!'); echo \$pid");
};
print "stdout $stdout\n";
print "stderr $stderr\n";
print "exit $exit\n";
Here I would have expected that $stdout would have given me the PID from the last echo command, but I got nothing.
Question
How do I get the PID of the remotely executed mbuffer in Perl, and so the Perl script isn't waiting for mbuffer to exit before continuing?
The problem seams to be that it is not possible to execute two commands in one system() or maybe it is, but not possible to get the output from the last command.
Creating a local helper script solved the problem.
#!/usr/bin/bash
# Redirection of stdin and stderr to files (preventing them from holding
# handles that connect, eventually, to the terminal).
read -r pid < <(ssh $1 "/usr/gnu/bin/nohup /opt/omni/bin/mbuffer -4 -s 128k -m 2G -v 0 -q -I 8023 >/tmp/mtest$2 </dev/null 2>/tmp/mtest.err & echo \$!")
echo $pid
and in Perl
my ($stdout, $stderr, $exit) = capture {
system("/comp/mbuffer-zfs-listen.sh 10.10.10.47 11");
};

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).

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

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.

bash lsof : get pid from one tty to another one

How to get the pid in tty1 of the process launched in tty2 ?
Context :
Trying to write a bash one-liner to kill a process generating a file when this file exceeds a pre defined max size. (The one-liner is not operating yet as it is as need to embed this into a loop).
During testing, the point is that lsof does not return any PID in the terminal tty1 despite the pid exists in the tty2 where the command is run.
tty1: generating the file and monitoring changes
MAX_SIZE_Ko=10001;file=test_lsof;dd if=/dev/zero of=$file bs=1k count=800;inotifywait $file;SIZE_Ko=$(du -s $file | cut -f1); [[ "$SIZE_Ko" -gt "$MAX_SIZE" ]] && ( PID=$(lsof $file | tail -n1 | awk -F" " '{ print $2 }') ; [[ ! -z $PID ]] && kill -9 $PID || echo "no running PID modifying $file" )
tty2 : increasing the file size
for (( 1; 1; 1));do echo -e "foobar\n" >> test_lsof; echo $(( i++ ))" - pid="$$; done
As mentioned in the other answer, the file is opened only for a short time, so the odds of your lsof catching it are low.
However, you can change that:
exec 5>test_lsof
for (( 1; 1; 1)); do
echo -e "foobar\n" >&5
echo $(( i++ ))" - pid="$$
done
This uses advanced shell redirection - the exec line opens a file descriptor, the >&5 redirects output from the command to that file descriptor.
If you do that, the shell will be visible to lsof.
The problem is that the process in tty2 opens the file only for a split second to append the string. Unless you run lsof in the same split second, you won't catch it.
One way to deal with this is to use inotify-tools. The program inotifywait allows you to wait until the file is opened and the run lsof, e.g. inotifywait $file; lsof $file.

Resources