Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

To be on safe side, I'd like bash abort the execution of a script if it encounters a syntax error.

To my surprise, I can't achieve this. (set -e is not enough.) Example:

#!/bin/bash

# Do exit on any error:
set -e

readonly a=(1 2)

# A syntax error is here:

if (( "${a[#]}" == 2 )); then
    echo ok
else
    echo not ok
fi

echo status $?

echo 'Bad: has not aborted execution on syntax error!'

Result (bash-3.2.39 or bash-3.2.51):

$ ./sh-on-syntax-err
./sh-on-syntax-err: line 10: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

Well, we can't check $? after every statement to catch syntax errors.

(I expected such safe behavior from a sensible programming language... perhaps this must be reported as a bug/wish to bash developers)

More experiments

if makes no difference.

Removing if:

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
(( "${a[#]}" == 2 ))
echo status $?
echo 'Bad: has not aborted execution on syntax error!'

Result:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

Perhaps, it's related to exercise 2 from http://mywiki.wooledge.org/BashFAQ/105 and has something to do with (( )). But I find it still unreasonable to continue executing afte a syntax error.

No, (( )) makes no difference!

It behaves bad even without the arithmetic test! Just a simple, basic script:

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
echo "${a[#]}"
echo status $?
echo 'Bad: has not aborted execution on syntax error!'

Result:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 
share|improve this question
    
set -e is not enough because your syntax error is in a if statement. Anywhere else should abort the script. –  jordanm Jul 8 '13 at 16:09
    
@jordanm Ok, this can be an explanation why set -e hasn't worked. But my question still makes sense. Is it possible to abort on any syntax error? –  imz -- Ivan Zakharyaschev Jul 8 '13 at 16:18
    
@jordanm Removed "if"; makes no diifference (updated my question). –  imz -- Ivan Zakharyaschev Jul 8 '13 at 16:25

4 Answers 4

Wrapping the whole into a function seems to do the trick:

#!/bin/bash -e

main () {
readonly a=(1 2)
    # A syntax error is here:
    if (( "${a[#]}" == 2 )); then
        echo ok
    else
        echo not ok
    fi
    echo status $?
    echo 'Bad: has not aborted execution on syntax error!'
}

main "$@"

Result:

$ ./sh-on-syntax-err 
$ ./sh-on-syntax-err line 6: #: syntax error: operand expected (error token is "#")
$ 

Though I have no clue why - maybe someone else can explain?

share|improve this answer
2  
Now your function definition is parsed and evaluated, and it fails. –  tripleee Jul 8 '13 at 17:00
    
Nice solution! BTW, it doesn't abort the whole program in this case, too. I've appended echo 'Bad2: has not aborted the execution after bad main!' as the last to your example, and the output is: $ LC_ALL=C ./sh-on-syntax-err ./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#") Bad2: has not aborted the execution after bad main! $ –  imz -- Ivan Zakharyaschev Jul 8 '13 at 17:32
    
But we shouldn't append a line simply then, we should put everything inside a function. –  imz -- Ivan Zakharyaschev Jul 8 '13 at 17:33
    
@tripleee Yes, it looks like parsing the function fails, so it is not complete, but the whole program is not aborted actually in this case (so it's not the effect of exit-on-error, probably). –  imz -- Ivan Zakharyaschev Jul 8 '13 at 17:34

You could make the script check itself by putting something like

bash -n "$0"

near the top of the script -- after set -e but before any significant piece of code.

I have to say this doesn't feel very robust, but if it works for you, perhaps it is acceptable.

share|improve this answer

You are probably mislead about the genuine meaning of set -e. A careful reading of the output of help set shows:

-e  Exit immediately if a command exits with a non-zero status.

So -e is about the exit status of commands being non-zero, not about syntax errors in your script.

In general, it is considered bad practice to use set -e, because all errors (i.e., all non-zero returns from commands) should be smartly handled by the script (think robust script, not the ones that go wild after you enter a filename with a space or that starts with a hypen).

Depending on the type of syntax error, the script might not even be executed at all. I'm not knowledgeable enough in bash to tell exactly what class of syntax errors (if only they can be classified) might lead to an immediate abortion of the script or not. Maybe some Bash gurus will join in and clarify everything.

I only hope I clarified the set -e statement!

About your wish:

I expected such safe behavior from a sensible programming language... perhaps this must be reported as a bug/wish to bash developers

The answer is definitely no! as what you've observed (set -e no responding as you're expecting) is in fact very well documented.

share|improve this answer
    
I meant the absence of such feature is a problem. I didn't want to focus on set -e -- it's just a bit close to my goals, that's why it is mentioned and used here. My question is not about set -e, it's about the unsafety of bash if it can't be made to abort on sytax errors. I'm looking for a way to make it always abort on syntax errors. –  imz -- Ivan Zakharyaschev Jul 8 '13 at 20:30

First, the (( )) in bash is used as arithmetic calculations, not to use in the if... use the [] for that.

Second, the ${a[#]} is weird and its is why is giving errors... the # doesn't have any array meaning

I don't know what you want to do with this, but I assume you want to know the number of fields, so you want ${#a[*]} instead

Finally, when comparing integers, the -eq is recommended over == (used for strings). the == will also work, but -eq is recommended.

so you want:

if [ ${#a[*]} -eq 2 ]; then 
share|improve this answer
    
Thank you for the correct code! –  imz -- Ivan Zakharyaschev Jul 8 '13 at 17:43
3  
That's not true. It's common to use the (( keyword with the if keyword. For example, if (( 5 * $b > 53 )). Unless you're aiming for portability with older shells, [[ is generally preferable over [. –  paraxor Jul 8 '13 at 19:11
2  
Yes, I agree with @Evan -- [[ and (( were designed specifically as lightweight tests to be used with "if" etc -- unlike [, they never spawn a subprocess to evaluate the condition. –  imz -- Ivan Zakharyaschev Jul 8 '13 at 20:33
1  
[ is a bash builtin. Older shells expect it to be its own program though. –  paraxor Jul 8 '13 at 21:24

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.