3

I want to make a build chain script, and I don't want it to perform until the end if there are error during compilation.

It's the first time I write a more "elaborated" script in bash, and it just doesn't work:

  1. it doesn't echo ERROR although I have lines with the word error in it
  2. whatever the value of testError, the script just hangs in the line

this is the code:

testError=false

output=$(scons)
while read -r line; do
    if [[ $line == .*[eE]rror.* ]] ; then echo 'ERROR' ; $testError = true ; fi #$testError = true fi
done

echo $testError
if  $testError  ; then exit ; fi;

... other commands

EDIT: Following all posters answers and Bash setting a global variable inside a loop and retaining its value -- Or process substituion for dummies and How do I use regular expressions in bash scripts?, this is the final version of the code. It works:

testError=false

shopt -s lastpipe
scons | while read -r line; do
  if [[ $line =~ .*[eE]rror.* ]] ; then
    echo -e 'ERROR' 
    testError=true 
  fi 
  echo -e '.'
done

if  $testError  ; then
    set -e 
fi

5 Answers 5

2

You set the value of testError in a subshell induced by your pipeline. When that subshell exits (at the end of the pipeline), any changes you made disappear. Try this:

while read -r line; do
   if [[ $line == .*[eE]rror.* ]] ; then
     echo -e 'ERROR' 
     testError=true 
   fi #$testError = true fi
done < <( scons )

or, if you don't want or can't use process substitution, use a temporary file

scons > tmp
while read -r line; do
  if [[ $line == .*[eE]rror.* ]] ; then
    echo -e 'ERROR' 
    testError=true 
  fi #$testError = true fi
done < tmp

This eliminates the pipeline, so the changes to testError persist after the while loop.

And, if your version of bash is new enough (4.2 or later), there is an option that allows the while loop at the end of a pipeline to execute in the current shell, not a subshell.

shopt -s lastpipe
scons | while read -r line; do
  if [[ $line == .*[eE]rror.* ]] ; then
    echo -e 'ERROR' 
    testError=true 
  fi #$testError = true fi
done
Sign up to request clarification or add additional context in comments.

1 Comment

if have version 4.2.24, that might do it.
1

You should try

set -e

this stops the script to continue if a command exit with a non zero status

or better

error_case() { # do something special; }
trap 'echo >&2 "an error occurs"; error_case' ERR

this run error_case function each time a command exit with a non zero status

See http://mywiki.wooledge.org/BashFAQ/105

Comments

1

Another bug is that you have spaces in the assignment. And skip the $

$testError = true

should be

testError=true

EDIT

testerror is changed in the subshell. Try

testerror=$(
    scons | while read -r line; do
        if [[ $line == .*[eE]rror.* ]] ; then
            echo true 
        fi #$testError = true fi
    done
)

Comments

1

Are you trying to parse the output of scons?

This:

output=$(scons)
while read -r line; do
    if [[ $line == .*[eE]rror.* ]] ; then 
        echo 'ERROR' 
        testError=true
    fi
done

does not do that. Perhaps you want:

scons | while read -r line; do ... ; done

5 Comments

The pipeline creates a subshell where changes to testError are no longer global.
@chepner I'm reading this question, related to what you're pointing: stackoverflow.com/questions/9012841/…
@chepner testError does not need to be global; it only needs to be referenced within the loop.
No, he is explicitly testing the value outside the loop.
@chepner But he should not be! The code can be simplified substantially, and this answer is merely intended to point out his major error: namely that he was not parsing the output of scons.
0

I answer also because other answers didn't notice: the use of regular expression should be done this way, using =~and not ==:

if [[ $line =~ .*[eE]rror.* ]] ; then
...

cf How do I use regular expressions in bash scripts?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.