mvdan / sh

A shell parser, formatter, and interpreter with bash support; includes shfmt
https://pkg.go.dev/mvdan.cc/sh/v3
BSD 3-Clause "New" or "Revised" License
7.1k stars 336 forks source link

Bug for associative arrays when using gosh with -c vs without #884

Closed everactivetim closed 2 years ago

everactivetim commented 2 years ago

I found this because task uses this and that's where it cropped up. So I came here and started trying to debug it and found gosh to use as a potential quick way to investigate.

It seems that when run without -c it iterates over each statement and executes them separately but when using -c it treats the whole file as a script. I guess there's something about context there that's being lost?

Anyway, consider this script:

#!/bin/bash

declare -A database_lookup=()
database_lookup[management]=management
database_lookup[devicetwin]=devicetwin
database_lookup[identity]=identity

for d in "${!database_lookup[@]}"
do
    echo "$d -- ${database_lookup[$d]}"
done

The output will be quite different depending on whether you use -c with gosh or not. This exactly models the behavior I am seeing in task.

Is this a bug or am I (and the task project by extension) doing it wrong? Thanks!

mvdan commented 2 years ago

Both seem to produce the same output on 5146d3eb581ae7f0b4f55a59d0c642fa5cea88d2:

$ cat input
#!/bin/bash

declare -A database_lookup=()
database_lookup[management]=management
database_lookup[devicetwin]=devicetwin
database_lookup[identity]=identity

for d in "${!database_lookup[@]}"
do
    echo "$d -- ${database_lookup[$d]}"
done
$ gosh <input
devicetwin identity management -- 
$ gosh -c "$(<input)"
devicetwin identity management -- 

That said, the result looks wrong. Bash gives:

$ bash <input
identity -- identity
devicetwin -- devicetwin
management -- management

I assume that's the bug you refer to - looking.

mvdan commented 2 years ago

Shorter repro:

$ cat input
declare -A arr=([a]=x [b]=y)
for k in "${!arr[@]}"; do
    echo "$k: ${arr[$k]}"
done
$ bash <input; echo ===; gosh <input
b: y
a: x
===
a b: