Search code examples
bashshellexit-code

set -e makes function stop running early?


I have a function that seems to break when I turn on errors with set -e. I suspect that it is working as intended but I can't see what I'm doing wrong.

Here is the function:

#!/usr/bin/env bash

set -e

my_function() {
    base_dir="/tmp/test"
    if [ ! -d $base_dir ]; then
        echo "Creating $base_dir"
        mkdir -p $base_dir
        touch $base_dir/some-file.txt
    fi

    is_edited=$(grep "foo" $base_dir/some-file.txt)

    if [ ! -z $is_edited  ]; then
        cd $base_dir
        echo "Doing stuff"
        docker run --rm debian ls
    fi

    echo
    echo "Done"
    echo
}

my_function

With set -e flipped on, the function returns seemingly without hit the echo statements. With set -e turned off, the echo statements get hit. What is happening and how do I fix this?


Solution

  • Try using:

    is_edited=$(grep "foo" $base_dir/some-file.txt || test $? -eq 1)
    

    The exit status of grep is 0 if it found a match, 1 if it didn't find a match, and 2 if it got an actual error. So if there's no match for foo in the file, it will be considered an error, and set -e will terminate the script. The above code translates 1 to a success, so the script will only terminate if grep gets a real error.

    If you don't care about terminating the script if grep gets an error, you could just use

    if grep -1 "foo" $base_dir/some-file.txt ; then
        ...
    fi
    

    The -q option makes it not print the matching line, just set its exit status based on whether it found a match.