Propagate exit code from runuser command - linux

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 \$?.

Related

Background rsync and pid from a shell script

I have a shell script that does a backup. I set this script in a cron but the problem is that the backup is heavy so it is possible to execute a second rsync before the first ends up.
I thought to launch rsync in a script and then get PID and write a file that script checks if the process exist or not (if this file exist or not).
If I put rsync in background I get the PID but I don't know how to know when rsync ends up but, if I set rsync (no background) I can't get PID before the process finish so I can't write a file whit PID.
I don't know what is the best way to "have rsync control" and know when it finish.
My script
#!/bin/bash
pidfile="/home/${USER}/.rsync_repository"
if [ -f $pidfile ];
then
echo "PID file exists " $(date +"%Y-%m-%d %H:%M:%S")
else
rsync -zrt --delete-before /repository/ /mnt/backup/repositorio/ < /dev/null &
echo $$ > $pidfile
# If I uncomment this 'rm' and rsync is running in background, the file is deleted so I can't "control" when rsync finish
# rm $pidfile
fi
Can anybody help me?!
Thanks in advance !! :)
# check to make sure script isn't still running
# if it's still running then exit this script
sScriptName="$(basename $0)"
if [ $(pidof -x ${sScriptName}| wc -w) -gt 2 ]; then
exit
fi
pidof finds the pid of a process
-x tells it to look for scripts too
${sScriptName} is just the name of the script...you can hardcode this
wc -w returns the word count by words
-gt 2 no more than one instance running (instance plus 1 for the pidof check)
if more than one instance running then exit script
Let me know if this works for you.
Test both for presence of pid file and status of the running process like this:
#!/bin/bash
pidfile="/home/${USER}/.rsync_repository"
is_running =0
if [ -f $pidfile ];
then
echo "PID file exists " $(date +"%Y-%m-%d %H:%M:%S")
previous_pid=`cat $pidfile`
is_running=`ps -ef | grep $previous_pid | wc -l`
fi
if [ $is_running -gt 0 ];
then
echo "Previous process didn't quit yet"
else
rsync -zrt --delete-before /repository/ /mnt/backup/repositorio/ < /dev/null &
echo $$ > $pidfile
fi
Hope this helps!!!

get return value of command run with script -c

Is there a way to capture the return value of a program run using script -c?
For example (in bash)
/bin/false; echo $? # outputs 1
/usr/bin/script -c "/bin/false" /dev/null; echo $?
# outputs 0 as script exited successfully.
I need to get the return value from /bin/false instead of from /usr/bin/script.. is this possible? I'm using script to trick a program into thinking it is running in a real tty even though it isn't... Thanks!
According to man script, using -e option will return the exit code of the child process.
-e, --return
Return the exit code of the child process.
Uses the same format as bash termination
on signal termination exit code is 128+n.
Here's some example.
$ /usr/bin/script -e -c "/bin/false" /dev/null; echo $?
1
$ /usr/bin/script -e -c "/bin/true" /dev/null; echo $?
0
$ /usr/bin/script -e -c "exit 123" /dev/null; echo $?
123

how to check whether one instance of shell script is already running - Linux

I have two different shell script say like
a.sh
b.sh
**code of a.sh**
#!/system/bin/sh
#some code
./xyz/b.sh &
Here we can see i am running b.sh through a.sh file which is postboot script. Each time when device gets reboot it is adding ./xyz/b.sh & which i am trying to avoid.
what i am trying to do :
i need to write a code in such a way that will find if ./system/xyz/b.sh & is already there then no need to add again.
Code :
if pgrep /xyz/b.sh > /dev/null 2>&1
then
echo aplog is running
exit 1
fi
these code is not running. Do not know where i am doing mistake.
Just try:
pgrep b.sh > /dev/null 2>&1
if [ 0 == $? ]
then
...
fi
pgrep will only work on process name, not full path to process name.
Try pgrep -f b.sh or pgrep -x b.sh instead of pgrep -x /xyz/b.sh
Hi test your file existence before creating it with:
filename="/fullpath/xyz/b.sh"
if [ -f "$filename" ]
then
echo "$filename found"
else
echo "$filename not found."
fi

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.

How to output return code in shell?

I'm trying to call a custom shell script through sh:
/bin/sh -c 'myscript.sh` >log.txt 2>&1 & echo $!
Output of this command is a PID of a created background process. I want to instruct /bin/sh to save return code of myscript.sh to some file. Is it possible?
echo $? >> /path/to/return_code
$? has the return code of the last statement in bash.
(/bin/sh -c "myscript.sh" >log.txt 2>&1 ; echo $? >somefile) & echo $!
(
/bin/sh -c 'myscript.sh` >log.txt 2>&1
echo $? > some_file
) &

Resources