0

Here's an extract from a bash script to reconfigure grub

    OLD="/etc/default/grub"
    NEW="/tmp/default.grub"
    SEC="1"

    cp "$OLD" "$NEW" || { >&2 echo "Couldn't copy $OLD" && exit 1; }

    sed -i "s/GRUB_TIMEOUT=[0-9]\+/GRUB_TIMEOUT=3/$SEC" "$NEW"

    cp_if_change_confirmed "$NEW" "$OLD"

    diff "$OLD" "$NEW" >/dev/null 2>&1 && \
    {
        CFG="$NEW.made"

        grub2-mkconfig --output="$CFG"

        echo "made $CFG from $NEW"

        cp_if_change_confirmed "$CFG" "/boot/grub2/grub.cfg"

        echo rm "$CFG"
        rm "$CFG"
    }

    echo rm "$NEW"
    rm "$NEW"

Those final echo and rm lines output

rm /tmp/default.grub.made
rm /tmp/default.grub.made
rm: cannot remove ‘/tmp/default.grub.made:‘ No such file or directory

Somehow NEW is being assigned the value of CFG.

Looking in cp_if_change_confirmed, which is a bash function, it contains

NEW="$1"

Which I guess explains the problem -- these variables don't have limited-enough scope.

But this is a maintenance problem -- I need to be able to include third party functions and know that they're not going to clobber values in the parent script.

Can I do this in bash, or is it a hopeless case and I just need to either be vigilant about variable names or use a real language?

  • In functions, use local. A real language would make sense for larger scripts, with Perl or Ruby you don't have to go that far from the shell syntax. – choroba Oct 7 '16 at 11:03
1

Use local. Note that bash has only function scope (like var in JavaScript), not block scope.

myfunc() {
    local foo bar=$1 baz=$2
    foo=/tmp/$bar
    echo "value inside: $foo, $bar"
}
foo=123 bar=234
myfunc quux
echo "value outside: $foo, $bar"

If you have a block that doesn't need any persistence, you can call a subshell using ( ... ):

foo=123
( foo=345; echo "value inside: $foo" )
echo "value outside: $foo"

Note that subshells have the full overhead of fork() – they're independent processes. Also they don't let you choose which variables to localize – it's all or nothing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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