Is it possible to run a command to redirect output and standard error in a file and know the return code of the command ?
./COMMANDE.sh 2>&1 | tee -a $LOG_DIRECTORY/$LOG_FILE
if [ $? = 0 ]; then
echo "OK"
else
echo "KO"
exit 1
fi
Currently, I get the return code of the tee command, I want to recover that of COMMANDE.sh.
You want PIPESTATUS.
./COMMANDE.sh 2>&1 | tee -a $LOG_DIRECTORY/$LOG_FILE
if [ ${PIPESTATUS[0]} = 0 ]; then
echo "OK"
else
echo "KO"
exit 1
fi
The index into the array ([0]) is the index of the command in the pipe chain just executed (./COMMANDE.sh). ${PIPESTATUS[1]} would be the tee.
Related
As all of you probably know, bash can print the last command exit code. This works for me, but I wanted to improve it by adding an if statement which checks if $? was 0. If it is 0 print the code in white, and if it is different, print it in red. Unfortunately this does not seem to work:
if [ $? == "0" ]; then
PS1=${PS1}'$(echo ${?})'
else
PS1=${PS1}'\e[1;31m\]$(echo ${?})'
fi
I also tried:
if [ $(echo $?) == "0" ]; then
PS1=${PS1}'$(echo ${?})'
else
PS1=${PS1}'\e[1;31m\]$(echo ${?})'
fi
also:
if [ $(echo ${?}) == "0" ]; then
PS1=${PS1}'$(echo ${?})'
else
PS1=${PS1}'\e[1;31m\]$(echo ${?})'
fi
None of them working.
Somehow variable is always 0, therefore printed in white.
How is it possible that I can print exit code, but cannot examine it with "if" ? Is this a bash limitation, or I am doing something wrong?
Just add $? to the PS1.
> PS1='PS $ '
> PS $ echo 1
> 1
> PS $ PS1='PS $? $ '
> PS 0 $ false
> PS 1 $ true
> PS 0 $
If you want to change color, you would have to do it inside PS1, not statically... Also note that $? will change it's value, so you need to save it.
PS1=${PS1}'$(ret=$?; if [ "$ret" -ne 0 ]; then printf "\e[1;31m\]"; fi; printf "%d" "$ret")'
$? is the exit status of the last command. If you execute some command, for instance [ … = … ], then $? changes. Example:
myCmd
echo $? # prints exit status of myCmd
echo $? # prints exit status of echo
myCmd
if [ $? = 0 ]; then
echo $? # prints exit status of `[`, here 0
else
echo $? # prints exit status of `[`, here 1
fi
Store the exit status of myCmd in a separate variable if you want to access it later.
myCmd
exitStatus=$?
echo $exitStatus # prints exit status of myCmd
echo $exitStatus # prints exit status of myCmd
By the way: "$(echo ${?})" is overly complicated; just "$?" is better in every way.
Hello I am new to shell script and I need to handle the error coming from a command being excuted inside echo like the following
echo -e "some internal command that I can't share \nq" | nc localhost 10000
I want to say
if [[ there's no error ]]
try
echo "YOUR SUPERSECRET COMMAND" | nc localhost 10000 | grep "Your expected error"
if [[ $? -eq 0 ]]; then
echo "Do something useful with error"
else
echo "Success"
fi
grep return 0 on matching and returns 1 when it doesn't find matching string.
The shell variable $? will give you the exit code. So, you could do:
echo -e "some internal command that I can't share \nq" | nc localhost 10000
rc=$?
if [[ $rc == 0 ]]; then
echo "success"
fi
Or simply,
if echo -e "some internal command that I can't share \nq" | nc localhost 10000; then
echo "success"
fi
Here is a concise way of doing it:
internalcommand &>/dev/null 2>&1 && echo OK || echo FAILED
If internalcommand succeeds OK will be printed to stdout, if it fails FAILED is printed.
Note tested on Bash v4
I'm trying to retrieve the code return from this script:
#!/bin/bash
echo "CM 1"
ssh -i key/keyId.ppk user#X.X.X.X "
grep blabla ddd
if [ ! $? -eq 0 ]; then exit 1; fi
"
echo $?
But the last command echo $? returns 0 instead of 1.
And if try to run separately (not as a script) :
the ssh command: ssh -i key/keyId.ppk user#X.X.X.X
grep blabla ddd => I get the msg "grep: ddd: No such file or directory"
then: if [ ! $? -eq 0 ]; then exit 1; fi
then: echo $? => it returns 1 as expected
Do you have an idea why it doesn't work in my script ?
Thank you
This code
ssh -i key/keyId.ppk user#X.X.X.X "
grep blabla ddd
if [ ! $? -eq 0 ]; then exit 1; fi
"
evaluates $? in your shell and not in the remote one, because the $ is not escaped in single quotes. You should escape that to reach desired behaviour. Once to avoid evaluation in your local shell, for the second time to avoid evaluation when it is passed to the bash on remote side. Or rather put the command into single quotes:
ssh -i key/keyId.ppk user#X.X.X.X '
grep blabla ddd
if [ ! $? -eq 0 ]; then exit 1; fi
'
The exit statements in each status check if statement do not break the while loop and truly exit the script. Is there something I can do to break the loop and exit with that $STATUS code?
EDIT: I've updated my code and it still isn't working. The status check if statements successfully break the loop but when I try to evaluate the $EXIT_STATUS it's always null, likely having something to do with scope. What am I missing here?
if [ $RESTART -le $STEP ]; then
. tell_step
while read XML_INPUT; do
XML_GDG=`get_full_name $GDG_NAME P`
cp $XML_INPUT $XML_GDG
STATUS=$?
EXIT_STATUS=$STATUS
if [ $STATUS -ne 0 ]; then
break
fi
add_one_gen $XML_GDG
STATUS=$?
EXIT_STATUS=$STATUS
if [ $STATUS -ne 0 ]; then
break
fi
done < $XML_STAGE_LIST
echo $EXIT_STATUS
if [ $EXIT_STATUS -ne 0 ]; then
exit $EXIT_STATUS
fi
fi
I had the same problem: when piping into a while loop, the script did not exit on exit. Instead it worked like "break" should do.
I have found 2 solutions:
a) After your while loop check the return code of the while loop and exit then:
somecommand | while something; do
...
done
# pass the exit code from the while loop
if [ $? != 0 ]
then
# this really exits
exit $?
fi
b) Set the bash script to exit on any error. Paste this at the beginning of your script:
set -e
Not really understand why your script dosn't exits on exit, because the next is works without problems:
while read name; do
echo "checking: $name"
grep $name /etc/passwd >/dev/null 2>&1
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "grep failed for $name rc-$STATUS"
exit $STATUS
fi
done <<EOF
root
bullshit
daemon
EOF
running it, produces:
$ bash testscript.sh ; echo "exited with: $?"
grep failed for bullshit rc-1
exited with: 1
as you can see, the script exited immediatelly and doesn't check the "daemon".
Anyway, maybe it is more readable, when you will use bash functions like:
dostep1() {
grep "$1:" /etc/passwd >/dev/null 2>&1
return $?
}
dostep2() {
grep "$1:" /some/nonexistent/file >/dev/null 2>&1
return $?
}
err() {
retval=$1; shift;
echo "$#" >&2 ; return $retval
}
while read name
do
echo =checking $name=
dostep1 $name || err $? "Step 1 failed" || exit $?
dostep2 $name || err $? "Step 2 failed" || exit $?
done
when run like:
echo 'root
> bullshit' | bash testexit.sh; echo "status: $?"
=checking root=
Step 2 failed
status: 2
so, step1 was OK and exited on the step2 (nonexisten file) - grep exit status 2, and when
echo 'bullshit
bin' | bash testexit.sh; echo "status: $?"
=checking bullshit=
Step 1 failed
status: 1
exited immediatelly on step1 (bullshit isn't in /etc/passwd) - grep exit status 1
You'll need to break out of your loop and then exit from your script. You can use a variable which is set on error to test if you need to exit with an error condition.
I had a similar problem when pipelining. My guess is a separate shell is started when piplining. Hopefully it helps someone else who stumbles across the problem.
From jm666's post above, this will not print 'Here I am!':
while read name; do
echo "checking: $name"
grep $name /etc/passwd >/dev/null 2>&1
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "grep failed for $name rc-$STATUS"
exit $STATUS
fi
done <<EOF
root
yayablah
daemon
EOF
echo "Here I am!"
However the following, which pipes the names to the while loop, does. It will also exit with a code of 0. Setting the variable and breaking doesn't seem to work either (which makes sense if it is another shell). Another method needs to be used to either communicate the error or avoid the situation in the first place.
cat <<EOF |
root
yayablah
daemon
EOF
while read name; do
echo "checking: $name"
grep $name /etc/passwd >/dev/null 2>&1
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "grep failed for $name rc-$STATUS"
exit $STATUS
fi
done
echo "Here I am!"
In the below code, I am trying to check if the command within the if condition completed successfully and that the data was pushed into the target file temp.txt.
Consider:
#!/usr/bin/ksh
A=4
B=1
$(tail -n $(( $A - $B )) sample.txt > temp.txt)
echo "1. Exit status:"$?
if [[ $( tail -n $(( $A - $B )) sample.txt > temp.txt ) ]]; then
echo "2. Exit status:"$?
echo "Command completed successfully"
else
echo "3. Exit status:"$?
echo "Command was unsuccessfully"
fi
Output:
$ sh sample.sh
1. Exit status:0
3. Exit status:1
Now I can't get why the exit status changes above.. when the output of both the instances of the tail commands are identical. Where am I going wrong here..?
In the first case, you're getting the exit status of a call to the tail command (the subshell you spawned with $() preserves the last exit status)
In the second case, you're getting the exit status of a call to the [[ ]] Bash built-in. But this is actually testing the output of your tail command, which is a completely different operation. And since that output is empty, the test fails.
Consider :
$ [[ "" ]] # Testing an empty string
$ echo $? # exit status 1, because empty strings are considered equivalent to FALSE
1
$ echo # Empty output
$ echo $? # exit status 0, the echo command executed without errors
0
$ [[ $(echo) ]] # Testing the output of the echo command
$ echo $? # exit status 1, just like the first example.
1
$ echo foo
foo
$ echo $? # No errors here either
0
$ [[ $(echo foo) ]]
$ echo $? # Exit status 0, but this is **NOT** the exit status of the echo command.
0