Two diagnostics that lied
- #bash-compat
- #diagnostics
- #pipelines
The last two rounds of this cascade fixed nothing about what huck does. Both were about what it says when something goes wrong — and a shell that reports the wrong thing costs you the ten minutes you spend believing it.
The line number that was off by one
# before
$ cat > two.sh <<'EOF'
set -u
echo "starting"
read line < $LIST | cat
EOF
$ bash two.sh
starting
two.sh: line 3: LIST: unbound variable
$ huck two.sh
starting
two.sh: line 2: LIST: unbound variableLine 2 is echo "starting" — a line with no variables on it at all. Follow that
report into a long script and you are reading the wrong command, wondering how
it could possibly be the one at fault.
The stale number came from a stage of a pipeline never announcing its own line.
huck stamps the current line when it sets up an external stage, but the same
stamp never happened for a stage the shell runs itself — a builtin like read,
here — so the error carried whatever line had been stamped last. Its three
neighbours (an external stage, a { … } group, a plain command with no pipe)
were all correct already, which is what pointed at the stage loop as the place
that owed the stamp.
# after
$ huck two.sh
starting
two.sh: line 3: LIST: unbound variableThe file that was never named
# before
$ cat > div.sh <<'EOF'
n=0
cat < $((10/n))
EOF
$ bash div.sh
div.sh: line 2: 10/n: division by 0 (error token is "n")
$ huck div.sh
div.sh: line 2: 10/n: division by 0 (error token is "n")
div.sh: line 2: : No such file or directoryThe arithmetic is wrong, both shells say so, and then huck says something else. There is no file in that command — the second line is the shell reporting that it could not open a filename that is the empty string, which is what the failed arithmetic left behind.
That is the whole bug: an expansion that fails still has to hand something back, and for arithmetic that something is the empty string. huck took the empty string as a filename and tried to open it. bash abandons the redirection at the error and says nothing further.
# after
$ huck div.sh
div.sh: line 2: 10/n: division by 0 (error token is "n")The fix had to keep the neighbouring case working, and it is a near-miss worth
naming: a word that expands to nothing — echo hi > $unset — or to several
fields is genuinely bash's ambiguous redirect, and that message still has to
appear. The difference is whether an error was already reported. Only when
nothing has gone wrong yet does an unusable word deserve a complaint of its own.
What this cascade fixed, end to end
Five rounds from one issue: a redirection failing under set -u ended the whole
shell instead of the command; a pipeline stage's words were expanded last
instead of first, so a failure in them took the pipeline down, leaked an
internal message and erased the stage from PIPESTATUS; and these two
diagnostics. Still open from the same hunt: time is not implemented as a
reserved word (#756), a
redirection inside a $( ) goes missing when huck quotes a word back at you
(#761), and bash has an
oddity of its own where set -e exits 1 after a failure whose $? reads 127
(#757).