Discussion:
Misbehavior with constants and bash script
Alexander Reintzsch
2018-11-19 20:04:21 UTC
Permalink
Hello,

I think I have found some unexpected behavior related to constants in
bash scripts. I have attached the short proof of concept bash script.

Usually bash scripts continue when they face an error with one command
but this script shows some weired behavior. It exits all the functions
it has called without executing the remaining commands and the continues
to run in the top scope of the script.

This only happens when a constant declared with
declare -r myConst="myConstantValue"
is attempted to be redefined using
myConst="new value"
but not with
declare myConst="new value"

This behavior doesn't seem right.

I have tried this on Ubuntu 16.04 LTS with bash version
GNU bash, Version 4.3.48(1)-release (x86_64-pc-linux-gnu)

Cheers,
Alex
Alexander Reintzsch
2018-11-19 21:44:38 UTC
Permalink
Hello,

I think I have found some unexpected behavior related to constants in
bash scripts. Here is a bash script as a short proof of concept.

#!/bin/bash
function foo
{
echo "A"
declare -r vconst="I am fixed."
echo "B"
declare vconst="new value"
echo "C"
unset vconst
echo "D"
vconst="new value"
echo "E" # not executed
}

function bar
{
echo "before foo"
foo
echo "after foo" # not executed
}

function buzz
{
echo "before bar"
bar
echo "after bar" # not executed
}

foo
bar
buzz
echo "the last line"

Usually bash scripts continue with the next command if they face an error with one command
but this script shows some weird behavior. It exits all the functions
it has called without executing the remaining commands and the continues
to run in the top scope of the script.

This only happens when a constant declared with
declare -r myConst="myConstantValue"
is attempted to be redefined using
myConst="new value"
but not with
declare myConst="new value"

This behavior doesn't seem right.

I have tried this on Ubuntu 16.04 LTS with bash version
GNU bash, Version 4.3.48(1)-release (x86_64-pc-linux-gnu)

Cheers,
Alex
Chet Ramey
2018-11-19 23:38:12 UTC
Permalink
On 11/19/18 3:04 PM, Alexander Reintzsch wrote:
> Hello,
>
> I think I have found some unexpected behavior related to constants in
> bash scripts. I have attached the short proof of concept bash script.
>
> Usually bash scripts continue when they face an error with one command
> but this script shows some weired behavior. It exits all the functions
> it has called without executing the remaining commands and the continues
> to run in the top scope of the script.
>
> This only happens when a constant declared with
> declare -r myConst="myConstantValue"
> is attempted to be redefined using
> myConst="new value"
> but not with
> declare myConst="new value"
>
> This behavior doesn't seem right.

OK, let's unpack this.

The variable assignment without declare has the posix semantics, in that
it constitutes a variable assignment error. When the shell is in posix
mode, it exits. When not in posix mode, the shell returns to the top level
and continues execution. It could return to the previous execution context
-- a virtual `return' -- or exit as it does in posix mode but has never
done so.

When the assignment is used as an argument to `declare', it causes the
declare command to fail, but it's not a variable assignment error, so
the script simply continues as with any other failed command.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
Quentin L'Hours
2018-11-20 00:06:23 UTC
Permalink
Hi Chet,

On 2018-11-19 03:38 PM, Chet Ramey wrote:
> When the assignment is used as an argument to `declare', it causes the
> declare command to fail, but it's not a variable assignment error, so
> the script simply continues as with any other failed command.

I remembered this email thread about declaration utilities splitting
behavior:
https://lists.gnu.org/archive/html/help-bash/2018-01/msg00006.html

If declaration utilities splitting is modified to be similar to a basic
assignment then wouldn't it make sense to do the same for the rest (in
this case assigment errors)?

It feels like POSIX progressively wants declaration builtins to have the
same rules as basic assignments, why should assignment error stay different?

--
Quentin
Chet Ramey
2018-11-20 00:14:11 UTC
Permalink
On 11/19/18 7:06 PM, Quentin L'Hours wrote:
> Hi Chet,
>
> On 2018-11-19 03:38 PM, Chet Ramey wrote:
>> When the assignment is used as an argument to `declare', it causes the
>> declare command to fail, but it's not a variable assignment error, so
>> the script simply continues as with any other failed command.
>
> I remembered this email thread about declaration utilities splitting behavior:
> https://lists.gnu.org/archive/html/help-bash/2018-01/msg00006.html
>
> If declaration utilities splitting is modified to be similar to a basic
> assignment then wouldn't it make sense to do the same for the rest (in this
> case assigment errors)?
>
> It feels like POSIX progressively wants declaration builtins to have the
> same rules as basic assignments, why should assignment error stay different?

Because the declaration utilities distinction only matters for expansion
purposes. I'm not really interested in going beyond what posix is willing
to standardize here. The expansion and word splitting issues solve
problems; I don't see extending that to exiting as useful.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
Alexander Reintzsch
2018-11-20 11:38:12 UTC
Permalink
Hello Chet,

thank you for your help and pointing to the posix behavior.

Quoting
https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html
"[...]
A non-interactive shell exits with an error status if a variable assignment error occurs when no command name follows the assignment statements. A variable assignment error occurs, for example, when trying to assign a value to a readonly variable.
[...]"

This helps. So what I need to do to force the script to proceed is to add another command after the assignment statement.

Before ist was

echo "A"
declare -r vconst="I am fixed."
echo "B"
vconst="new value" # fails here
echo "C" # never reached

and if I add an empty command after the assignment statement it behaves as expected.

echo "A"
declare -r vconst="I am fixed."
echo "B"
vconst="new value" : # please note the : at the end. (no operation command)
echo "C" # now printed

End then it does not matter if bash is in posix mode or not.

Thank you for your help in that matter.

Cheers,
Alex
Chet Ramey
2018-11-20 14:39:43 UTC
Permalink
On 11/20/18 6:38 AM, Alexander Reintzsch wrote:

> and if I add an empty command after the assignment statement it behaves as expected.
>
> echo "A"
> declare -r vconst="I am fixed."
> echo "B"
> vconst="new value" : # please note the : at the end. (no operation command)
> echo "C" # now printed

I would use `true'. `:' is a special builtin, and a POSIX interpretation
clarified that a non-interactive shell is supposed to exit if a variable
assignment error occurs when the assignment precedes a special builtin.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
Loading...