Search code examples
bashshell

Why does the (( compound command assign to a variable in this case?


$ test=false
$ echo $test
false
$ ((!test))
((test=false))
$ echo $?
1
$ echo $test
0

Why is test now 0? I dont understand where or why (( is assigning to test or why it prints ((test=false)). This only happens when writing the commands manually on the terminal; when running those same commands as a script test stays on "false".


Solution

  • Firstly, test and false are also the names of builtins which aren't relevant here, so for the sake of clarity, I'm going to change them to foo and bar

    $ foo=bar
    
    $ echo $foo
    bar
    

    !foo is history expansion, and the matching command is foo=bar.

    $ echo !foo
    echo foo=bar
    foo=bar
    
    $ ((!foo))
    ((foo=bar))
    
    $ echo $?
    1
    
    • The extra line below the command there is a preview of the command that's being run. I'm not sure what the technical term for that is.
    • History expansion is turned off in scripts.

    In an arithmetic context, the string bar is treated as a variable name, but that variable isn't defined, so it's evaluated as 0. Hence foo=0.

    $ echo $foo
    0