Shell Scripting ssh execution of commands - linux

I have no idea, how to execute this specific combined shell script command via ssh on a remote device.
#!/bin/bash
cmd=""
command="restart"
case "$command" in
restart)
cmd+="pkill -f fileA.py;"
cmd+="python3 -u fileA.py >> fileA.log &"
;;
*)
echo "Unknown command"
esac
cmd=$(ssh root#foobar $cmd)
The error that occurs is:
pkill -f fileA.py;python3 -u fileA.py >> fileA.log &
pkill: invalid user name: fileA.py
I know that the whole string is interpreted as one command, but that's not what I want to achive.
I appreciate any help.

Are you sure you pasted the right code? That pkill error messages comes from using the -u or
-U options. Please check that first.
Next, your lack of quotes is causing you problems. After the shell substitutes the variables, you have this:
cmd=$(ssh root#foobar pkill -f fileA.py;python3 -u fileA.py >> fileA.log &)
So you're killing the process on the remote system, and launching it on the local system.
I think you really need this:
case "$command" in
restart)
cmd="pkill -f fileA.py; nohup python3 -u fileA.py >> fileA.log & disown"
;;
*)
echo "Unknown command"
esac
cmd=$(ssh root#foobar bash -c "$cmd")
nohup and disown allow the backgrounded process to keep running after the shell exits.

Related

Using tee with bash hangs with some scripts

I have a simple script file startsql.sh to start mysql:
#!/bin/bash
#Script to Start MySQL
echo "Starting MySQL"
if sudo service mysqld start; then
echo "MySQL started successfully!"
else
echo "Error: Failure to start MySQL" 1>&2
exit 1
fi
I run it using:
bash startsql.sh |& tee -a scriptlogs.log
Though the service seems to start successfully, the command hangs after showing the messages on the command window. It works fine without hanging if I remove the tee. Interestingly I have a similar script to stop mysql and it works fine without issues. I checked and find no difference between the two scripts.
After searching a lot, I found that using the below works, but the side effect of this is that the tee process is still running in the background
bash startsql.sh > >( tee -a scriptlogs.log) 2>&1
Can someone please help me understand why does using tee hang on some occasions.
Will you teach me the version of bash?
If you use bash 3.2.57, the error occure like this.
$ bash ./startsql.sh |& tee -a output.txt
bash ./startsql.sh |& tee -a output.txt
bash: syntax error near unexpected token `&'

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 this bash script can't get the pid of the background process by $!

I have a script like that:
su lingcat -c PHPRC\=\/home\/lingcat\/etc\/php5\
PHP_FCGI_CHILDREN\=4\ \/usr\/bin\/php\-loop\.pl\ \/usr\/bin\/php5\-cgi\ \-b\
127\.0\.0\.1\:9006\ \>\>\/home\/lingcat\/logs\/php\.log\ 2\>\&1\ \<\/dev\/null\ \&\
echo\ \$\!\ \>\/var\/php\-nginx\/135488849520817\.php\.pid
This is working. But there is too many \ in the script, they make the code unreadable. So, I wrote a new shell script:
#!/bin/sh
case "$1" in
'start')
su biergaizi -c "PHPRC=/home/biergaizi/etc/php5 PHP_FCGI_CHILDREN=2
/usr/bin/php-loop.pl /usr/bin/php-cgi -b /var/run/virtualhost/php5-fpm-biergaizi.test.sock >>/home/biergaizi/logs/php.log 2>&1 </dev/null &
echo $! > /var/php-nginx/biergaizi.test.php.pid"
RETVAL=$?
;;
'stop')
su biergaizi -c "kill `cat /var/php-nginx/biergaizi.test.php.pid` ; sleep 1"
RETVAL=$?
;;
'restart')
$0 stop ; $0 start
RETVAL=$?
;;
*)
echo "Usage: $0 { start | stop }"
RETVAL=1
;;
esac
exit
But /var/php-nginx/biergaizi.test.php.pid is empty.
What's wrong?
The .pid file is empty, because $! gets substituted by the shell executing your script, instead of the shell executing the commands you pass through su. And as there is no recently started background command in your script, it substitutes an empty string. So, shell started by su executes simply echo > /var/php-nginx/biergaizi.test.php.pid.
To prevent that, quote your command passed to su using single quotes, instead of double quotes. It is better to do that to the "stop" command as well. Like this:
su biergaizi -c 'PHPRC=/home/biergaizi/etc/php5 PHP_FCGI_CHILDREN=2
/usr/bin/php-loop.pl /usr/bin/php-cgi -b /var/run/virtualhost/php5-fpm-biergaizi.test.sock >>/home/biergaizi/logs/php.log 2>&1 </dev/null &
echo $! > /var/php-nginx/biergaizi.test.php.pid'
And this:
su biergaizi -c 'kill `cat /var/php-nginx/biergaizi.test.php.pid` ; sleep 1'
See http://www.gnu.org/software/bash/manual/html_node/Quoting.html for details.
try this:
Escape $ from $!, before passing to su -c.

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"'

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