If we call this script with the following command line
$ sh runner.sh ls -l
the 'ls -l' command will be executed.
Now, if a call the script with the commands
$ sh runner.sh A=B
we get the following errors:
runner.sh: 10: runner.sh: A=B: not found
That's not what happens in any conforming implementation of sh (see below).
Why the shell does not treat the first string in "$@" ('A=B'
in these cases) as the first possibile token of command (which
is an assignemnt)?
Probably because the script that you presented isn't representative of the
issue, in so far as you weren't using eval at the time.
In addition, the problem is NOT solved by using 'eval "$@"'.
Apparently it works. For example the command
$ sh runner.sh A=BCD
works, but
$ sh runner.sh A="B CD"
gives an error. In this case the error (I think) comes
from the way the expansion of "$@" is performed: eval has to evaluate the
string "A=B CD", so it treats A=B as an assignemnt and 'CD' as
a command.
This is correct.
I think that your questions may be addressed overall by reading
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02.
As concerns potential variable assignments that are the leading words of a simple
command, the parser will only interpret them as such in the case that each of the
applicable tokens contains an <equals-sign> and is not quoted in any way. Thus,
the following examples do not work in the way that you might have imagined.
$ set -- A=B
$ "$1"
bash: A=B: command not found
$ 'A=B'
bash: A=B: command not found
$ \A=B
bash: A=B: command not found
Conversely, the following example works because the parameter expansion is
performed prior to the resulting word(s) being injected into the tokeniser by
eval. The observed token ends up being A=B, literally.
$ set -- 'A=B'
$ eval "$1"