On Mon, Aug 24, 2026 at 5:00 PM Chet Ramey <[email protected]> wrote:
>
> On 8/23/26 8:04 PM, Zachary Santer wrote:
> > given the current locale's collation order.
> >
> > I'm actually struggling to find where the devel branch's doc/bash.1
> > bothers to say that the expansion of indexed arrays subscripted by @
> > or * is in numerical order of indices and the expansion of associative
> > arrays subscripted by @ or * is in arbitrary order.
>
> It doesn't specify expansion order at all.
>
> It makes the most sense to expand indexed arrays in ascending order of
> indices, to sort of mirror C arrays. It doesn't make sense to impose
> some kind of ordering on associative arrays, which are essentially
> dicts/hash tables.

If it's not documented, it can change at any time.

> > When expansion order matters at all, this is liable to be what the
> > shell programmer would prefer. ${!assoc[@]} expanding in lexicographic
> > order would make for a slight improvement in one of my scripts, at
> > least.
>
> This is not a feature that has been in great demand (or any demand,
> really), especially not sorting in lexicographic order for keys.

For context, the script in question is assigning to the keys of an
associative array as just a way to avoid duplicate entries. A bunch of
assoc[${entry}]=''
and then
"${!assoc[@]}"
to recover the entries after that's done. There are too few entries to
justify piping things into 'sort --unique'. Everything else in the
script is in alphabetical order, just because all the commands it
calls output data in alphabetical order. But here, it's combining the
output from multiple commands.

> If you want to wait for the next devel branch push, I added a -I option
> to the `asort' loadable builtin to sort an associative array by keys
> and assign those keys in order to an indexed array. (The existing -i
> option is like awk's asorti, which sorts by values and then assigns the
> keys, so it was only a small change.) See if that does what you want
> without any other changes.

"make loadables" failed for me, this morning. I've attached the output
if you're interested. Remember, I'm building bash in MSYS2 MSYS on a
Windows box. I don't know that I can work with loadable builtins. (Mr.
Marsh may not have realized that you have to build the loadable
builtin yourself, actually.)

It would be nice to see 'asort' promoted to, uh, built-in builtin.
Until that happens, there's a fairly big barrier to using it in a
production script that I expect other people to run on their own
machines.

It would also be nice to see a -u unique option, for that matter.

> > I can't imagine a scenario where a script would depend upon an
> > associative array expanding in not necessarily a sorted order, but
> > this functionality could be controlled by a shopt option.
>
> I think if such a feature were to be implemented, it would be better
> to implement it as a parameter transformation. When you need it, you
> get it.

On the other hand, if it's always there, you get it in contexts where
there's no way to easily apply that parameter transformation -
'declare -p', ${assoc[@]@k}, ${assoc[@]@K}, I don't know what else. I
guess ${!assoc[@]} wouldn't count, because it's easy enough to do
declare -a array=( "${!assoc[@]}" )
array=( "${array[@]@S}" )

This would at least make it easier to hunt through 'declare -p assoc' output.

> > Maybe it
> > would save a few clock cycles if the programmer doesn't care. On the
> > other hand, how would bash handle this shopt option being enabled
> > after associative arrays have already been assigned to?
>
> I don't think a shopt option is the way to go, but why would it matter?
> You only want an expansion, right? So you get a sorted expansion, where
> the ordering is whatever the current locale says it is at expansion time.

You'd also want different parameter transformations for different
comparison functions: ${array[@[@s} to sort by ascending integers and
${array[@]@S} to sort lexicographically, maybe. The second you want a
third comparison function, or want to remove duplicates as well,
you're all out of "S"es. I hesitate to say that a single ${array[@]@S}
could change its behavior based on whether the -i integer attribute is
set on the array variable being expanded or not.

> > So that linked list

Or something more useful, like a red-black tree. Yes, I should
actually look at the source code some time.

> > would have to be maintained throughout the
> > lifetime of the indexed array. The same would go for associative
> > arrays with keys sorted.
make[1]: Entering directory '/home/zsant/repos/bash/builtins'
make[1]: 'pipesize.h' is up to date.
make[1]: Leaving directory '/home/zsant/repos/bash/builtins'

          ***********************************************************
          *                                                         *
          * GNU bash, version 5.4.0(1)-devel (x86_64-pc-cygwin)
          *                                                         *
          ***********************************************************

cd /home/zsant/repos/bash/examples/loadables && make  all
make[1]: Entering directory '/home/zsant/repos/bash/examples/loadables'
gcc -shared -Wl,--enable-auto-import -Wl,--enable-auto-image-base 
-Wl,--export-all -Wl,--out-implib=print.a   -o print print.o 
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
print.o: in function `print_builtin':
/home/zsant/repos/bash/examples/loadables/print.c:86:(.text+0x24): undefined 
reference to `reset_internal_getopt'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:87:(.text+0x33): undefined 
reference to `internal_getopt'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:126:(.text+0x61): undefined 
reference to `builtin_usage'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:112:(.text+0x8b): undefined 
reference to `all_digits'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:112:(.text+0xa7): undefined 
reference to `valid_number'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
print.o: in function `printargs':
/home/zsant/repos/bash/examples/loadables/print.c:180:(.text+0x19c): undefined 
reference to `ansicstr'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
print.o: in function `print_builtin':
/home/zsant/repos/bash/examples/loadables/print.c:124:(.text+0x261): undefined 
reference to `builtin_help'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:141:(.text+0x2bc): undefined 
reference to `make_word'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:142:(.text+0x2c7): undefined 
reference to `make_word_list'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:143:(.text+0x2d2): undefined 
reference to `printf_builtin'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
/home/zsant/repos/bash/examples/loadables/print.c:145:(.text+0x2e5): undefined 
reference to `dispose_words'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
print.o:print.c:(.rdata$.refptr.list_optarg[.refptr.list_optarg]+0x0): 
undefined reference to `list_optarg'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
print.o:print.c:(.rdata$.refptr.loptend[.refptr.loptend]+0x0): undefined 
reference to `loptend'
/usr/lib/gcc/x86_64-pc-cygwin/15.3.0/../../../../x86_64-pc-cygwin/bin/ld: 
print.o:print.c:(.rdata$.refptr.lcurrent[.refptr.lcurrent]+0x0): undefined 
reference to `lcurrent'
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:129: print] Error 1
make[1]: Leaving directory '/home/zsant/repos/bash/examples/loadables'
make: *** [Makefile:906: loadables] Error 2

Reply via email to