shell script: incorrect exit status of executed command - shell

I'd like to get exit status of the command passed as argument (to my sh script called a.sh).
I've tried:
#!/bin/sh
CMD="$#"
echo "arg passed CMD: $CMD"
($CMD) >/dev/null 2>&1
res=$?
echo "exit status: $res"
CMD="echo aaa | grep -q zzz"
echo "in script CMD: $CMD"
($CMD) >/dev/null 2>&1
res=$?
echo "exit status: $res"
Once executing:
./a.sh 'echo aa | grep -q zzz'
arg passed CMD: echo aa | grep -q zzz
exit status: 0
in script CMD: echo aaa | grep -q zzz
exit status: 0
However if I run the command directly in shell I see:
/bin/sh -c 'echo aa | grep -q zzz ; echo $?'
1
How should my script look like, to get the correct status 1 instead of 0 of the executed command?

$(CMD) output were aaa | grep -q zzz that is why it return with exit 0. Just remove the redirection to /dev/null and you will see.
You could use eval to run commands from variables.
#!/bin/sh
CMD="$#"
echo "arg passed CMD: $CMD"
eval $CMD >/dev/null 2>&1
res=$?
echo "exit status: $res"
CMD="echo aaa | grep -q zzz"
echo "in script CMD: $CMD"
eval $CMD >/dev/null 2>&1
res=$?
echo "exit status: $res"

Related

how to escape a shell command in bash script written by another bash script

Can anybody show me how to escape a shell command in bash script written by another bash script ?
For example my script looks like:
sudo sh -c "echo \"if who | grep tty | grep \`whoami\` > /dev/null\" > test.sh"
sudo sh -c "echo \"then\" >> test.sh"
sudo sh -c "echo \" echo ' log in '\" >> test.sh"
sudo sh -c "echo \"else\" >> test.sh"
sudo sh -c "echo \" exit\" >> test.sh"
sudo sh -c "echo \"fi\" >> test.sh"
I want that the script test.sh contains
if who | grep tty | grep `whoami`> /dev/null
then
echo 'user is log in '
else
exit
fi
Actually the command whoami is replaced by root.
Solution:
sudo tee /usr/local/bin/test.sh << 'EOF'
if who | grep tty | grep `whoami`> /dev/null
then
echo 'user is log in '
else
exit
fi
EOF
Complex quotes are most easily handled with a heredoc:
cat > test.sh << 'EOF'
if who | grep tty | grep `whoami`> /dev/null
then
echo 'user is log in '
else
exit
fi
EOF

Why is exit my status valid in command line but not within bash script? (Bash)

There are a few layers here, so bear with me.
My docker-container ssh -c"echo 'YAY!'; exit 25;" command executes echo 'YAY!'; exit 25; in my docker container. It returns:
YAY
error: message=YAY!
, code=25
I need to know if the command within the container was successful, so I append the following to the command:
docker-container ssh -c"echo 'YAY!'; exit 25;" >&1 2>/tmp/stderr; cat /tmp/stderr | grep 'code=' | cut -d'=' -f2 | { read exitStatus; echo $exitStatus; }
This sends the stderr to /tmp/stderr and, with the echo $exitStatus returns:
YAY!
25
So, this is exactly what I want. I want the $exitStatus saved to a variable. My problem is, I am placing this into a bash script (GIT pre-commit) and when this exact code is executed, the exit status is null.
Here is my bash script:
# .git/hooks/pre-commit
if [ -z ${DOCKER_MOUNT+x} ];
then
docker-container ssh -c"echo 'YAY!'; exit 25;" >&1 2>/tmp/stderr; cat /tmp/stderr | grep 'code=' | cut -d'=' -f2 | { read exitStatus; echo $exitStatus; }
exit $exitStatus;
else
echo "Container detected!"
fi;
That's because you're setting the variable in a pipeline. Each command in the pipeline is run in a subshell, and when the subshell exits the variable are no longer available.
bash allows you to run the pipeline's last command in the current shell, but you also have to turn off job control
An example
# default bash
$ echo foo | { read x; echo x=$x; } ; echo x=$x
x=foo
x=
# with "lastpipe" configuration
$ set +m; shopt -s lastpipe
$ echo foo | { read x; echo x=$x; } ; echo x=$x
x=foo
x=foo
Add set +m; shopt -s lastpipe to your script and you should be good.
And as Charles comments, there are more efficient ways to do it. Like this:
source <(docker-container ssh -c "echo 'YAY!'; exit 25;" 2>&1 1>/dev/null | awk -F= '/code=/ {print "exitStatus=" $2}')
echo $exitStatus

Why is this pipeline behave differently in ksh93 compared to bash?

I had an issue with a ksh93 code. As it was very complex I started reducing it to an example code that will reproduce the same issue. I ended up with this:
set -o pipefail;
{
echo "progress" 1>&3 | false
} 3>&1 | cat | \
while read pv_output; do
echo "meanwhile ... we got "
echo $pv_output | cat
done
echo $?
When I run this code with ksh93 it outputs "0", when I run it with bash it outputs "1".
# echo "ksh93";ksh93 ./x1.sh ;echo "bash"; bash ./x1.sh
ksh93
meanwhile ... we got
progress
0
bash
meanwhile ... we got
progress
1
However if I start fiddling with the code, and remove the first cat, both shells return "1"
set -o pipefail;
{
echo "progress" 1>&3 | false
} 3>&1 | \
while read pv_output; do
echo "meanwhile ... we got "
echo $pv_output | cat
done
echo $?
Or... if I leave in the first cat, but I remove the second one from inside the while, they work the same way again.
set -o pipefail;
{
echo "progress" 1>&3 | false
} 3>&1 | cat | \
while read pv_output; do
echo "meanwhile ... we got "
echo $pv_output
done
echo $?
Now, for this example I used cat for simplicity's sake. In real life the first cat is actually an awk processing the output of a complicated command. The second cat is actually a sed. I mention these, so that it is clear that the cat command in itself is not the culprit.

Bash Script issue, command not found, PATH seems to be correct

I have a issue with my Script, i am just trying to fingure out if my screen session is running or not (line 19).
The rest of the script is working.
#!/bin/bash
echo $PATH // /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
echo "0"
content=$(wget http://interwebs.com/index.php?page=count -q -O -)
z=$(($content / 5))
z=$(($z + 1))
echo $z // 4
lockfile=/var/tmp/mylock
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# do stuff here
x=1
count=0
while [ $x -le $z ]
do
$req ="$(ps -ef | grep -i mystatus$count | grep -v grep)"
if [ "$req" = "" ]; then
# run bash script
screen -amds mystatus$count /usr/bin/wget --spider interwebs.com/index.php?page=cronwhatsoever$(( $count +1))-$(( $count +5))
else
echo "Cron running"
fi
x=$(( $x + 1 ))
count=$(( $count +5))
done
# clean up after yourself, and release your trap
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi
sleep 15
It returns line 19: =: command not found. Actually running:
ps -ef | grep -i bukkit | grep -v grep
Works without issues if i run it directly in my Terminal, so any idea how to solve this issue?
I guess it something PATH related but grep is located in /bin/grep.
$req ="$(ps -ef | grep -i mystatus$count | grep -v grep)"
should be
req="$(ps -ef | grep -i mystatus$count | grep -v grep)"
Don't use $ on the left-hand side of an assignment, and you must not have spaces around the =

tee and pipelines inside a bash script

i need to redirect stout and stderr in bash each to separate file.
well i completed this command:
((/usr/bin/java -jar /opt/SEOC2/seoc2.jar 2>&1 1>&3 | tee --append /opt/SEOC2/log/err.log) 3>&1 1>&2 | tee --append /opt/SEOC2/log/app.log) >> /opt/SEOC2/log/combined.log 2>&1 &
which works fine running from a command line.
trying to put the very same command into bash script
...
12 cmd="(($run -jar $cmd 2>&1 1>&3 | tee --append $err) 3>&1 1>&2 | tee --append $log) >> $combined 2>&1"
...
30 echo -e "Starting servis..."
31 $cmd &
32 pid=`ps -eo pid,args | grep seoc2.jar | grep -v grep | cut -c1-6`
33 if [ ! -z $pid ]; then
...
leads to error like this:
root#operator:/opt/SEOC2# seoc2 start
Starting servis...
/usr/local/bin/seoc2: line 31: ((/usr/bin/java: dir or file doesn't exist
tried to cover this command by $( ), ` ` etc but with no effect at all :(
any suggestion or advice would be very appreciated, playing around for hours already :/
thanx a lot
Rene
If you store the whole command line in a variable you have to use eval to execute it:
cmd="(($run -jar $cmd 2>&1 1>&3 | tee --append $err) 3>&1 1>&2 | tee --append $log) >> $combined 2>&1"
...
eval $cmd &

Resources