TL; DR: en el caso de export FOO=bar, bash invoca la creación de su entorno temporal, se establece FOO=baren ese entorno y luego produce un comando final de export FOO. En ese punto, FOOse toma como último argumento.
Ah, el muy maltratado $_:
($ _, un guión bajo). Al iniciar el shell, establezca el nombre de ruta absoluto utilizado para invocar el shell o el script de shell que se ejecuta como se pasa en el entorno o la lista de argumentos. Posteriormente, se expande hasta el último argumento del comando anterior, después de la expansión. Establezca también el nombre de ruta completo utilizado para invocar cada comando ejecutado y colocado en el entorno exportado a ese comando. Al verificar el correo, este parámetro contiene el nombre del archivo de correo.
Veamos algunas variaciones:
$ man; echo $_
What manual page do you want?
man
$ man foo; echo $_
No manual entry for foo
foo
$ echo; echo $_
echo
$ echo bar foo; echo $_
bar foo
foo
$ foo=x eval 'echo $foo'; echo $_
x
echo $foo
$ bar() { man $1; }; echo $_
foo
$ for (( i=0; $i<0; i=i+1 )); do echo $i; done; echo $_
foo
$ bar; echo $_
What manual page do you want?
man
$ bar foo; echo $_
No manual entry for foo
foo
$ MANPATH=/tmp; echo $_
$ export MANPATH=/tmp; echo $_
MANPATH
Entonces vemos tres patrones aquí:
- Los comandos invocados desde el sistema de archivos, las funciones y las funciones incorporadas se comportan como generalmente se espera:
$_se configura con el nombre del comando en sí mismo si no hay argumentos; de lo contrario, el último de los argumentos presentados.
- Después de las definiciones de funciones, bucles y otras construcciones lógicas:
$_no se modifica.
- Todo lo demás:
$_se establece en algo que no se espera del todo; extraño.
He instrumentado el código para proporcionar una idea de la rareza.
$ ./bash --noprofile --norc -c 'man foo'
lastword=[man]
lastarg=[foo]
$ ./bash --noprofile --norc -c 'export FOO=bar'
lastword=[export]
lastarg=[FOO=bar]
bind_variable, name=[FOO], value=[bar]
before bind_lastarg, lastarg=[FOO]
bind_lastarg, arg=[FOO]
bind_variable, name=[_], value=[FOO]
$ ./bash --noprofile --norc -c 'declare FOO=bar'
lastword=[declare]
lastarg=[FOO=bar]
bind_variable, name=[FOO], value=[(null)]
before bind_lastarg, lastarg=[FOO=bar]
bind_lastarg, arg=[FOO=bar]
bind_variable, name=[_], value=[FOO=bar]
Puede ver que el analizador ve el último argumento esperado ( lastarg=) en todos los casos, pero lo que sucede a partir de entonces depende de lo que bash piense que debería suceder. Ver execute_cmd.c, execute_simple_command () .
En el caso de export FOO=bar, bash realiza la asignación y luego exporta la variable. Esto parece coherente con la afirmación de la documentación de que el último argumento se calculó después de la expansión.
EDITORes un argumento para exportar