On Mon, 24 Jun 2024 10:50:15 -0600, Rob Gardner <robma...@gmail.com> wrote:

[reformatted]

> $ readarray -d ' ' X <<< "A B C"

This does not remove the separator, so X[0] ends up containing "A ", X[1]
contains "B ", and X[2] contains "C\n" (as there was no trailing
space to terminate the string).
See:

$ declare -p X
declare -a X=([0]="A " [1]="B " [2]=$'C\n')

> $ ./printarg ${X[0]}A
> 65 0 65 $

You are not quoting the expansion. This means that your C code is receiving
TWO arguments, namely "A" and "A". Remember that in C, strings are
NUL-terminated. While you only print argv[1], you're printing too many
characters (you go up until n+2), so your code ends up printing 65 (the
first "A"), 0 (the string terminator), and 65 again (the second "A", which
presumably is contiguous in memory).
So your code is printing 0 simply because in C, strings are NUL-terminated
and you're reading that NUL and one character past it. Nothing to do wth
bash.

For completeness, if you quote the expansion, you get (at least on my
system):

$ ./printarg "${X[0]}A"
65 32 65 0 83

That is, "A", a space, and "A" again (which is the result of the quoted
expansion), 0 for the string terminator, and a random 83 which is
whatever follows in memory (strangely, it seems to be 83 consistently
though). Again, nothing to do with bash.

> $ read -d ' ' -a   Y <<< "A B C"

This only reads "A" into Y. Without quotes, the result is the same as in
the first example, except that Y[0] contains "A", not "A ", so when the
expansion takes place, the two "A"'s are concatenated and the C code sees
"AA".

$ declare -p Y
declare -a Y=([0]="A")

$ ./printarg ${Y[0]}A    # or "${Y[0]}A", here there's no difference
65 65 0 83


> $ readarray -td ' ' Z <<< "A B C"

This produces

$ declare -p Z
declare -a Z=([0]="A" [1]="B" [2]=$'C\n')

> $ ./printarg ${Z[0]}A
> 65 65 0 83 $

This is again correct given all the above. The only issue I see is that
your C code is reading too many characters from the string it's given.

--
D.

Reply via email to