Normally, in bash, if I wanted to loop until a command produced a certain output I'd do this:
while : ; do
status=$(mycommand)
[ "$status" = "whatever" ] && break
printf "."
sleep 10
done
But how would I do that I wanted to loop until I got stderr output? I thought maybe I could do this:
while : ; do
status=$(mycommand 2>&1)
[ "$status" = "whatever" ] && break
printf "."
sleep 10
done
But when I do that I get this error:
-bash: syntax error near unexpected token `2' error.
Any ideas?
Related
I am trying to detect whenever the following script (random_fail.sh) fails --which happens rarely-- by running it inside a while loop in the second script (catch_error.sh):
#!/usr/bin/env bash
# random_fail.sh
n=$(( RANDOM % 100 ))
if [[ n -eq 42 ]]; then
echo "Something went wrong"
>&2 echo "The error was using magic numbers"
exit 1
fi
echo "Everything went according to plan"
#!/usr/bin/env bash
# catch_error.sh
count=0 # The number of times before failing
error=0 # assuming everything initially ran fine
while [ "$error" != 1 ]; do
# running till non-zero exit
# writing the error code from the radom_fail script into /tmp/error
bash ./random_fail.sh 1>/tmp/msg 2>/tmp/error
# reading from the file, assuming 0 written inside most of the times
error="$(cat /tmp/error)"
echo "$error"
# updating the count
count=$((count + 1))
done
echo "random_fail.sh failed!: $(cat /tmp/msg)"
echo "Error code: $(cat /tmp/error)"
echo "Ran ${count} times, before failing"
I was expecting that the catch_error.sh will read from /tmp/error and come out of the loop once a particular run of random_fail.sh exits with 1.
Instead, the catch script seems to be running forever. I think this is because the error code is not being redirected to the /tmp/error file at all.
Please help.
You aren't catching the error code in the proper/usual manner. Also, no need to prefix the execution with the "bash" command, when it already contains the shebang. Lastly, curious why you don't simply use #!/bin/bash instead of #!/usr/bin/env bash .
Your second script should be modified to look like this:
#!/usr/bin/env bash
# catch_error.sh
count=0 # The number of times before failing
error=0 # assuming everything initially ran fine
while [ "$error" != 1 ]; do
# running till non-zero exit
# writing the error code from the radom_fail script into /tmp/error
./random_fail.sh 1>/tmp/msg 2>/tmp/error
error=$?
echo "$error"
# updating the count
count=$((count + 1))
done
echo "random_fail.sh failed!: $(cat /tmp/msg)"
echo "Error code: ${error}"
echo "Ran ${count} times, before failing"
[ "$error" != 1 ] is true if random_fail.sh prints a lone digit 1 to stderr. As long as this doesn't happen, your script will loop. You could instead test whether there has been written anything to stderr. There are several possibilities to achieve this:
printf '' >/tmp/error
while [[ ! -s /tmp/error ]]
or
error=
while (( $#error == 0 ))
or
error=
while [[ -z $error ]]
/tmp/error will always be either empty or will contain the line "The error was using magic numbers". It will never contain 0 or 1. If you want to know the exit value of the script, just check it directly:
if ./random_fail.sh 1>/tmp/msg 2>/tmp/error; then error=1; else error=0; fi
Or, you can do:
./random_fail.sh 1>/tmp/msg 2>/tmp/error
error=$?
But don't do either of those. Just do:
while ./random_fail.sh; do ...; done
As long as random_fail.sh (please read https://www.talisman.org/~erlkonig/documents/commandname-extensions-considered-harmful/ and stop naming your scripts with a .sh suffix) returns 0, the loop body will be entered. When it returns non-zero, the loop terminates.
I have a simple script that tries to curl and URL and echo a string if it failed or succeeded. But I get the following warnings, depending on how I form this if statement.
Depending on the quotes I use in the statement below I get the following warnings:
: -ne: unary operator expected
: integer expression expected
With the alternative check (as comment), I get the following error
((: != 0 : syntax error: operand expected (error token is "!= 0 ")
The script:
c=`curl -s -m 10 https://example.com` || ce=$?
#if (( ${je} != 0 )); then
if [ ${ce} -ne 0 ]; then
echo "Failed"
else
echo "Succeeded"
fi
How do I correctly check the return value of the curl command in a bash if-statement?
The problem is that you only set the exit status when the curl command fails.
If the command succeeds, then variable ce is not set (and also not quoted) and the test executes if [ -ne 0 ]; then and prints the error message.
Quoting the variable alone wouldn't help in this case, you would just get a different error message.
To fix this, set variable ce after the curl command no matter what the exit status of the curl command is:
c=$(curl -s -m 10 https://example.com)
ce=$?
if [ "$ce" -ne 0 ]; then
echo "Failed"
else
echo "Succeeded"
fi
Or shorter without exit status variable:
c=$(curl -s -m 10 https://example.com)
if [ $? -ne 0 ]; then
echo "Failed"
else
echo "Succeeded"
fi
I am unsure what is causing this error. Script continues to run and enters the "if" statement without issues.
"./test.sh: line 79: [: too many arguments"
if [ grep -Fq "variable=00000000000" /home/me/test.txt ] ; then #line 79
........
........
else
echo "hi"
fi
[ ... ] is not part of the syntax of an if statement. [ is a command name, that requires a final argument of ] to simulate the look of syntax.
Drop them if you want to run a different command whose exit status if should check.
if grep -Fq "..." /honme/me/test.txt; then
Simply use :
if grep -Fq "variable=00000000000" /home/me/test.txt; then
[...]
or
grep -Fq "variable=00000000000" /home/me/test.txt && echo 'true'
Explanations
Every command have a return code that you can display with :
true
echo $? # return 0, true in bash
false
echo $? # return 1: false in bash
It's named boolean logic
So I have a shell script that contains a big if/fi block, and it was working fine until I decided to place an else case for this big if/fi block. Now I am getting this error:
/root/VVPN/Scripts/scriptPrincipal.sh: line 201: syntax error near unexpected token `else'
/root/VVPN/Scripts/scriptPrincipal.sh: line 201: `else'
I went through 8~10 stackoverflow posts where people had exactly the same error, except that all of them were simple syntax errors like a missing space after the [ of the if statement, or a : instead of a ; before the then keyword, or an else intended for an if that was already closed with a fi, etc... (you get the idea :p).
However I've checked my code for all these errors over and over and everything seems to be correct when it comes to if/else/fi syntax. I even showed the code to some colleagues and they too couldn't find the reason for this error.
Here's the code:
if [ ${CP} != "continue" ]
then
echo 'Downloading the necessary files from the server...'
# If folder F*** doesn't exist in /root/VVPN/Numbers
if [ ! -d ${N} ]
then
# Create folders F***, and F***/Results
mkdir ${N}
mkdir ${N}/Results
cd ${N}
# Get real number to factorize from server (e.g: wget server.com:8000/route/to/F1067/F1067)
ROUTE="VVPN/Numbers/${N}/${N}"
REAL_NUM_FILENAME=${N}
while true
do
wget --retry-connrefused --tries=inf -q ${SERVER}/${ROUTE} -O ${REAL_NUM_FILENAME} --continue
if [ $? -eq 0 ]; then
break
fi
sleep 1
done
# Get ECM-Program tuned for this number from server (e.g: wget server.com:8000/route/to/F1067/ecm)
ROUTE="VVPN/Numbers/${N}/ecm"
PROGRAM_NAME='ecm'
while true
do
wget --retry-connrefused --tries=inf -q ${SERVER}/${ROUTE} -O ${PROGRAM_NAME} --continue
if [ $? = 0 ]; then
break
fi
sleep 1
done
else
# The folder already exists, now we have to check whether the number has ",c" label or not
cd ${N}
fi
# Give the permission to execute program
chmod +x ecm
# Make 6 directories, one for each SPE
for i in {1..6}
do
mkdir "SPE${i}"
cp ecm "SPE${i}/"
done
# if there is no checkpoints:
if [ $CP = $N ]
then
# Get currentSigma for this number from server (e.g : wget server.com:8000/rout/to/F1067/currentSigma.txt)
ROUTE="VVPN/Numbers/${N}/currentSigma"
REAL_FILE_NAME='sigma'
while true
do
wget --retry-connrefused --tries=inf -q ${SERVER}/${ROUTE} -O ${REAL_FILE_NAME} --continue
if [ $? = 0 ]; then
break
fi
sleep 1
done
else
#The number has a ",c" label (= w/ checkpoint)
# Get i (server sigma) and C (current job counter) from the server (e.g: wget server.com:8000/route/to/F1067/icy)
ROUTE="icy?number=${N}"
SIGMA_C_Y='icy'
while true
do
wget --retry-connrefused --tries=inf -q ${SERVER}/${ROUTE} -O ${SIGMA_C_Y} --continue
if [ $? = 0 ]; then
break
fi
sleep 1
done
i=$(cat ${SIGMA_C_Y} | cut -d "," -f1)
C=$(cat ${SIGMA_C_Y} | cut -d "," -f2)
Y=$(cat ${SIGMA_C_Y} | cut -d "," -f3)
echo $i > sigma
echo $C > /root/VVPN/Scripts/C
# Get the checkpoints from the server
ROUTE="VVPN/Numbers/${N}/CP/${i},${C},${Y}"
for speNum in {1..6}
do
SPE="SPE${speNum}"
touch $SPE/again
for bigX in {0..3}
do
CHECKPOINT="pointsCurve${bigX}.${Y}"
while true
do
wget --retry-connrefused --tries=inf -q ${SERVER}/${ROUTE}/${SPE}/${CHECKPOINT} -O ${CHECKPOINT} --continue
if [ $? = 0 ]; then
mv $CHECKPOINT $SPE
break
fi
sleep 1
done
done
done
fi
cd ..
else
echo "Found ${N}'s folder on this PS3"
fi
So the else mentioned in the error (at line 201) is actually the last else in the code. The script works fine without this else and the echo that comes right after.
Any help would be much appreciated :)
Could you change if [ $CP = $N ] as below;
if [ "$CP" == "$N" ]
This is not if else problem; For example; if you run the following code, output is same. So You should focus other commands inside if statement.
CP="continue1"
if [ ${CP} != "continue" ]
then
while #this is wrong
echo ok
echo ok
echo ok
else
fi
./test.sh: line 8: syntax error near unexpected token `else'
./test.sh: line 8: `else'
I am facing the syntax error near unexpected token,elif error for the following code.
if [ "$1" == "abc" ]; then
echo "abc"
elif [ "$1" == "xyz" ]; then
echo "xyz"
else
echo "Unkown parameter"
exit 0
fi
Error is:
abc.sh: line 28: syntax error near unexpected token elif'
abc.sh: line 28:elif [ "$1" == "xyz" ]; then
Code seems alright but only point I would like to add is the OS on which you are running. The == works fine with Linux RedHat/Suse or some solaris machine but on some OS like Hpux or AIX it don't work. You should use = which is correct as you are comparing strings.