I have the following variables set in a script.
SU="/bin/su -s /bin/sh
WSO2_SCRIPT="JAVA_HOME=$JAVA_HOME /opt/autopilot/wso2is/bin/wso2server.sh"
WSO2_USER=autoplt
This part of the script is of concern:
if [ "$RETVAL" -eq "0" ]; then
if [ "$(whoami)" != "${WSO2_USER}" ]; then
$SU - $WSO2_USER -c "${WSO2_SCRIPT} start" >> ${WSO2_LOG} 2>&1 || RETVAL="4"
else
${WSO2_SCRIPT} start >> ${WSO2_LOG} 2>&1 || RETVAL="4"
fi
fi
If I am root, then the following command gets executed:
/bin/su -s /bin/sh - autoplt -c 'JAVA_HOME=/usr/java/latest /opt/autopilot/wso2is/bin/wso2server.sh start'
and
RETVAL
will get evaluated to 0.
When I am user autoplt, the following command gets executed:
JAVA_HOME=/usr/java/latest /opt/autopilot/wso2is/bin/wso2server.sh start
However
RETVAL
will get evaluated to 4?
Are they not the same commands? Shouldn't RETVAL be 0 in each case?
The command gets executed successfully when I run it in the shell as autoplt user.
Therefore is there something wrong with the way I have written it?
the double pipe || used in lines :
$SU - $WSO2_USER -c "${WSO2_SCRIPT} start" >> ${WSO2_LOG} 2>&1 || RETVAL="4"
${WSO2_SCRIPT} start >> ${WSO2_LOG} 2>&1 || RETVAL="4"
means if the first command succeed, then the second will not be executed
It means when running as root, it succeed then no change to RETVAL
and as a user, if fails so change RETVAL to 4
Related
I am trying to run multiple jobs at once and need to write which one failed to a log file. How to do it? I tried to point the result to a log file but it's not getting populated.
sh test1.sh & test_1_Pid=$!
sh test2.sh & test_2_Pid=$!
wait $test_1_Pid
test_1_Pid=$?
wait $test_2_Pid
test_2_Pid=$?
Start your script in a subshell and let each subprocess handle the errors.
(sh test1.sh || echo "test1" >> failure.txt)&
(sh test2.sh || echo "test2" >> failure.txt)&
Or perhaps without a subprocess:
sh test1.sh || echo "test1" >> failure.txt&
sh test2.sh || echo "test2" >> failure.txt&
Demo:
touch job1 job2 job4 job5 job7
rm result # when you repeat the demo
for ((j=1; j<8;j++)); do
(sleep 2; rm job$j 2>/dev/null || echo "job$j failed" >> result)&
done
wait
cat result
The result will show the files that you did not create.
job3 failed
job6 failed
I am trying to build a bash script to run a web server. I need the script to show output of web server in console until specific word appears on the console indicating either the server initialization completed successfully or some error occurs.
I was able to show the console output until timeout occurs:
#!/bin/bash
(exec /opt/aspnetcore-runtime-3.0.0-linux-x64/dotnet /opt/app/Launcher.dll &) | (timeout --foreground 6 cat; cat > /dev/null &)
If an error happens earlier than 6 seconds, then the web server stopped and the control goes back to the terminal, which is the desired behavior.
However, if the web server initialization was successfully completed in 2 seconds, the user must wait for another 4 seconds until the script finishes. I want to return the control back to terminal once some phrase (e.g. SUCCESS INIT!) appear on the console.
On surface, replacing the current wait ('cat') with a custom loop that will exit when 'SUCCESS INIT!' is found will address the problem
Such a loop can be implemented with
while read x && echo "$x" && [ "$x" != "SUCCESS INIT!" ] ; do : ; done
And the combined command
(Launch-command &) | (timeout --foreground 6 sh -c 'while read x && echo "$x" && [ "$x" != "SUCCESS INIT!" ] ; do : ; done' ; cat > /dev/null &)
Not very elegant. If you can, put the 'timeout ... while ...' in a separate script. I did not test, but it should work:
#! /bin/bash
# wait-line.sh
timeout --foreground "$1" sh -c "while read x && echo "$x" && [ "$x" != "$2" ] ; do : done "
cat > /dev/null
And then the original command line will look like
( Launch-command ... & ) | ( wait-line.sh 6 "SUCCESS INIT!" &)
I am running a shell script from another shell script which is a git-hook pre-push.
This is the content of .git/hooks/pre-push:
#!/usr/bin/env bash
protected_branch='master'
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
if [ $protected_branch = $current_branch ]; then
sh test.sh
if [ $? != 0 ]; then
echo "Error"
exit 1
fi
else
exit 0
fi
This is the content of test.sh:
#!/bin/bash
run_base=1
run_test () {
read -p "enter varname: " varname
echo $varname
}
time {
if [ "$run_base" = "0" ] ; then
echo "skipped"
else
time { run_test ; }
echo "run_test done";
fi
}
If I run pre-push script directly, then it works fine, but it doesn't work when I execute git push origin master and pre-push gets triggered automatically.
read in test.sh is not being executed when I trigger the pre-push hook script. Do I need to do anything specific in order to execute read in test.sh which is called from pre-push?
I just test it on my computer and it works perfectly,
isoto#hal9014-2 ~/w/test> ./pre-push
enter varname: asd
asd
real 0m1.361s
user 0m0.000s
sys 0m0.000s
run_test done
real 0m1.361s
user 0m0.000s
sys 0m0.000s
So, the only thing that I did was to add executable permissions, chmod +x *
And also I put both scripts in the same directory, besides everything should work.
Found the answer, I had to add < /dev/tty at the end of read:
read -p "enter varname: " varname < /dev/tty
echo $varname
I have a shell snippet:
nohup sudo node server.js >> node.log 2>&1 &
if [ $? -eq 0 ]; then
echo $! $?
echo $! > pids
fi
What I expect is if the node server.js run normaly, then record the pid of this process to the file: pids.
But it does'nt work, the $? is always 0 because it is the status of sudo process?
And the $! is also not the pid of the process of node command.
So how can I get the correct return code and pid of the node server.js in the above shell script?
My final solutions:
#!/usr/bin/env bash
ROOT=$(cd `dirname $0`; pwd)
sudo kill -9 `cat ${ROOT}/pids` || true
nohup sudo node server.js >> node.log 2>&1 &
sleep 1
pid=$(ps --ppid $! | tail -1 | awk '{ print $1 }')
if echo $pid | egrep -q '^[0-9]+$'; then
echo $pid > ${ROOT}/pids
else
echo 'server not started!'
fi
When you run a command in the background, there's no sensible way for the shell to get the return code without waiting for the process to finish (i.e., node is no longer running). Therefore even these have return code 0:
$ false &
$ does_not_exist &
It seems what you want to do is to check whether a daemon started properly, which completely depends on the daemon. In your case you've started a Node.js server, so you could simply run something like this (untested):
test_if_server_is_running() {
tries=10
while [ "$tries" -gt 0 ]
do
let tries--
wget http://127.0.0.1/some_server_path && return
sleep 1
done
return 1 # Did not start up in at least 10 seconds
}
When I run the following script in Bash 3.2.48:
#!/bin/bash
export var1='var1'
echo "UID=$UID"
if [ x"$UID" != x"0" ]
then
export var2='var2'
while ! { sudo -v; }; do { sudo -v; }; done;
sudo $0
exit
fi
echo $var1
echo $var2
exit 0
What I get as output is:
UID=1000
UID=0
var1
Why is var2 not exported and echoed? I'm pretty sure that the same script worked with older Bash versions.
you enter first time with UID == 1000, you enter the if clause
you sudo to execute the script with UID == 0;
sudo doesn't preserve the environment if env_reset is set in /etc/sudoers (default in most distros). You need sudo -E to preserve env.
you exit (before echoing)
from the sudo call you enter with clean env.
you enter with UID == 0
you don't enter the if clause, var2 is not set
you echo the variables.
The answer is much more simpler than is seems: you never echo those vars (when not running as root, obviously), because you already exit :))
Try avoiding/minimizing confusion by adding more appropriate/concise debug statements. For instance, use a single echo that contains everything that's relevant to your problem (i.e. process ID, user ID, var1, var2):
#!/bin/bash
export var1='var1'
if [ "$UID" != "0" ] ; then
export var2='var2'
while ! { sudo -v; }; do { sudo -v; }; done;
sudo $0
# this is "the key exit" ;-)
#exit
fi
echo "pid=[$$] uid=[$UID] var1=[$var1] var2=[$var2]"
With the exit commented out you get what you expect (obviously, in the "parent" process, as the "child" one - the one running as "root" - never reaches that part of the code that exports var2):
pid=[12346] uid=[0] var1=[var1] var2=[]
pid=[12345] uid=[1] var1=[var1] var2=[var2]
++ sometimes running scripts in debug mode (bash -x) helps too ;-)