On Sat, Aug 24, 2024, at 10:08 PM, Steffen Nurpmeso wrote: > One hopefully last thing in this regard for me, > > c() { echo "$# 1<$1> 2<$2> 3<$3> *<$*> @<$@>"; }
This easily obfuscates the structure of the "$@" expansion. You'd be better off with something like this, which prints each positional parameter as "<...>". c() { printf '%s *<%s> @' "$#" "$*" printf '<%s>' "$@" echo } > set -- a\ b c\ d e\ f > .. > echo 3 > IFS= > c $* > c $@ > c "$*" > c "$@" > .. > > gives a diff of > > 3 > -3 1<a b> 2<c d> 3<e f> *<a bc de f> @<a b c d e f> > -3 1<a b> 2<c d> 3<e f> *<a bc de f> @<a b c d e f> > +1 1<a bc de f> 2<> 3<> *<a bc de f> @<a bc de f> > +1 1<a bc de f> 2<> 3<> *<a bc de f> @<a bc de f> > 1 1<a bc de f> 2<> 3<> *<a bc de f> @<a bc de f> > 3 1<a b> 2<c d> 3<e f> *<a bc de f> @<a b c d e f> > > So here the unquoted $* is expanded with $IFS=NUL, the variable $* > was resolved to the string "a bc de f" because the first character > of $IFS is NUL; this string gets the word split, but since no > character of $IFS ever matches (but the terminating NUL), no split > occurs. How is the shell capable to reconstruct the original > parameters "a b", "c d", and "e f", as there is no field > separator. > (The only thinkable answer is that the step that my MUA does, > namely resolving $* as a single string first, does not happen, > right? I really have to carefully read the standard on Monday.) Correct. Since you're using $* unquoted in a context where field splitting is performed, the shell does not expand it to a single field. The bash manual says [1]: * ($*) Expands to the positional parameters, starting from one. When the expansion is not within double quotes, each positional parameter expands to a separate word. In contexts where it is performed, those words are subject to further word splitting and filename expansion. When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable. That is, "$*" is equivalent to "$1c$2c", where c is the first character of the value of the IFS variable. If IFS is unset, the parameters are separated by spaces. If IFS is null, the parameters are joined without intervening separators. POSIX.1-2024 says [2]: * Expands to the positional parameters, starting from one, initially producing one field for each positional parameter that is set. When the expansion occurs in a context where field splitting will be performed, any empty fields may be discarded and each of the non-empty fields shall be further split as described in 2.6.5 Field Splitting. When the expansion occurs in a context where field splitting will not be performed, the initial fields shall be joined to form a single field with the value of each parameter separated by the first character of the IFS variable if IFS contains at least one character, or separated by a <space> if IFS is unset, or with no separation if IFS is set to a null string. [1]: https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html#index-_002a [2]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_05_02 -- vq