Skip to content

Instantly share code, notes, and snippets.

@abathur
Last active Dec 23, 2020
Embed
What would you like to do?
hmm

I was trying to debug something and stumbled into some weird bash behavior. I assume it's just a caveat I'm unaware of, but I've looked around in the docs for a bit and haven't found any explanations.

It seems like there's some small distinction/bug between simple commands, and command lists. (context: https://www.gnu.org/software/bash/manual/html_node/Shell-Commands.html)

Basically:

  1. set a variable readonly
  2. try to modify the variable
  3. try to do something else
    • something else runs if
      • you do it all in a single simple command
      • you do it at the root of the document with newlines
    • something else is skipped if it is in any kind of command list

There's an output file with the result from bash, (bash-based) sh, and osh. I see the behavior in both 3.2 and modern bash.

#!/usr/bin/env bash
PS4=$'\t'
set -x
readonly sigh=1
sigh=2
: reached
sigh=2a; : skipped
sigh=2b || : skipped
sigh=2c : reached
if : if always true ; then
sigh=3a : reached
sigh=3b; : skipped
sigh=3c
: skipped
fi
for x in {4..5}; do
sigh=$x
: skipped
done
(
sigh=6
: skipped
)
{
sigh=7
: skipped
}
: $(sigh=8 || : skipped)
what(){
sigh=9
: skipped
}
what
$ bash ../heh.sh
readonly sigh=1
sigh=1
sigh=2
../heh.sh: line 5: sigh: readonly variable
: reached
sigh=2a
../heh.sh: line 8: sigh: readonly variable
sigh=2b
../heh.sh: line 9: sigh: readonly variable
../heh.sh: line 10: sigh: readonly variable
: reached
: if always true
../heh.sh: line 13: sigh: readonly variable
: reached
sigh=3b
../heh.sh: line 14: sigh: readonly variable
for x in {4..5}
sigh=4
../heh.sh: line 17: sigh: readonly variable
sigh=6
../heh.sh: line 20: sigh: readonly variable
sigh=7
../heh.sh: line 25: sigh: readonly variable
sigh=8
../heh.sh: line 27: sigh: readonly variable
:
what
sigh=9
../heh.sh: line 30: sigh: readonly variable
$ sh ../heh.sh
readonly sigh=1
sigh=1
sigh=2
../heh.sh: line 5: sigh: readonly variable
$ osh ../heh.sh
'TODO: trace string for assignment'
sigh=2
^~~~~
../heh.sh:5: fatal: Can't assign to readonly value 'sigh'
#!/usr/bin/env bash
PS4=$'\t'
set -x
readonly sigh=1
unset sigh
: reached
unset sigh; : skipped
unset sigh || : skipped
# unset sigh : reached
if : if always true ; then
unset sigh; : skipped
unset sigh
: skipped
fi
for x in {4..5}; do
unset sigh
: skipped
done
(
unset sigh
: skipped
)
{
unset sigh
: skipped
}
: $(unset sigh || : skipped)
what(){
unset sigh
: skipped
}
what
$ bash ./unset.sh
readonly sigh=1
sigh=1
unset sigh
./unset.sh: line 7: unset: sigh: cannot unset: readonly variable
: reached
unset sigh
./unset.sh: line 10: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 11: unset: sigh: cannot unset: readonly variable
: skipped
: if always true
unset sigh
./unset.sh: line 15: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 16: unset: sigh: cannot unset: readonly variable
: skipped
for x in {4..5}
unset sigh
./unset.sh: line 21: unset: sigh: cannot unset: readonly variable
: skipped
for x in {4..5}
unset sigh
./unset.sh: line 21: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 26: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 31: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 35: unset: sigh: cannot unset: readonly variable
: skipped
:
what
unset sigh
./unset.sh: line 38: unset: sigh: cannot unset: readonly variable
: skipped
$ sh ./unset.sh
readonly sigh=1
sigh=1
unset sigh
./unset.sh: line 7: unset: sigh: cannot unset: readonly variable
: reached
unset sigh
./unset.sh: line 10: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 11: unset: sigh: cannot unset: readonly variable
: skipped
: if always true
unset sigh
./unset.sh: line 15: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 16: unset: sigh: cannot unset: readonly variable
: skipped
for x in {4..5}
unset sigh
./unset.sh: line 21: unset: sigh: cannot unset: readonly variable
: skipped
for x in {4..5}
unset sigh
./unset.sh: line 21: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 26: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 31: unset: sigh: cannot unset: readonly variable
: skipped
unset sigh
./unset.sh: line 35: unset: sigh: cannot unset: readonly variable
: skipped
:
what
unset sigh
./unset.sh: line 38: unset: sigh: cannot unset: readonly variable
: skipped
$ zsh ./unset.sh
readonly sigh=1
unset sigh
./unset.sh:7: read-only variable: sigh
# I think this is bugged, given how it handled the assignment
$ osh ../resholved/unset.sh
Tue Dec 22 2020 10:55:16 -->
'TODO: trace string for assignment'
unset sigh
unset sigh
^~~~
../resholved/unset.sh:7: Can't unset readonly variable 'sigh'
':' reached
unset sigh
unset sigh; : skipped
^~~~
../resholved/unset.sh:10: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
unset sigh || : skipped
^~~~
../resholved/unset.sh:11: Can't unset readonly variable 'sigh'
':' skipped
':' if always true
unset sigh
unset sigh; : skipped
^~~~
../resholved/unset.sh:15: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
unset sigh
^~~~
../resholved/unset.sh:16: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
unset sigh
^~~~
../resholved/unset.sh:21: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
unset sigh
^~~~
../resholved/unset.sh:21: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
unset sigh
^~~~
../resholved/unset.sh:26: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
unset sigh
^~~~
../resholved/unset.sh:31: Can't unset readonly variable 'sigh'
':' skipped
unset sigh
: $(unset sigh || : skipped)
^~~~
../resholved/unset.sh:35: Can't unset readonly variable 'sigh'
':' skipped
':'
what
unset sigh
unset sigh
^~~~
../resholved/unset.sh:38: Can't unset readonly variable 'sigh'
':' skipped
ipped
ipped
^~~~~
../resholved/unset.sh:42: 'ipped' not found
done
^~~~
../resholved/unset.sh:43: Unexpected word when parsing command
Oil version 0.8.5
Release Date: 2020-11-18 22:04:12+00:00
Arch: x86_64
OS: Darwin
Platform: Darwin Kernel Version 19.6.0: Mon Aug 31 22:12:52 PDT 2020; root:xnu-6153.141.2~1/RELEASE_X86_64
Compiler: GCC 4.2.1 Compatible Clang 7.1.0 (tags/RELEASE_710/final)
Interpreter: OVM
Interpreter version: 2.7.13
Bytecode: bytecode-opy.zip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment