Eso comenzó como un truco en el shell Bourne. En el shell Bourne, la división de palabras IFS se realizó (después de la tokenización) en todas las palabras en el contexto de la lista (argumentos de línea de comando o las palabras en las que se for
repiten los bucles). Si tuvieras:
IFS=i var=file2.txt
edit file.txt $var
Esa segunda línea se tokenised en 3 palabras, $var
se ampliaría, y dividir + glob se llevaría a cabo en las tres palabras, por lo que terminaría corriendo ed
con t
, f
, le.txt
, f
,le2.txt
como argumentos.
Citar partes de eso evitaría la división + glob. El shell Bourne inicialmente recordó qué caracteres fueron citados al establecer el octavo bit en ellos internamente (eso cambió más tarde cuando Unix se limpió a 8 bits, pero el shell aún hizo algo similar para recordar qué byte fue citado).
Ambos $*
y $@
fueron la concatenación de los parámetros posicionales con espacio intermedio. Pero hubo un procesamiento especial de $@
cuándo dentro de comillas dobles. Si está $1
contenido foo bar
y $2
contenido baz
, "$@"
se expandiría a:
foo bar baz
^^^^^^^ ^^^
(con la ^
s anterior que indica cuáles de los caracteres tienen el octavo bit establecido). Donde se citó el primer espacio (tenía el octavo bit establecido) pero no el segundo (el agregado entre palabras).
Y es la división IFS la que se encarga de separar los argumentos (suponiendo que el carácter de espacio esté $IFS
como está por defecto). Es similar a cómo $*
se expandió en su predecesor el shell Mashey (basado en el shell Thomson, mientras que el shell Bourne se escribió desde cero).
Eso explica por qué en el shell Bourne inicialmente "$@"
se expandiría a la cadena vacía en lugar de nada en absoluto cuando la lista de parámetros posicionales estaba vacía (tenía que evitarlo ${1+"$@"}
), por qué no mantuvo los parámetros posicionales vacíos y por qué "$@"
no no funciona cuando$IFS
no contiene el carácter de espacio.
La intención era poder pasar la lista de argumentos literalmente a otro comando, pero eso no funcionó correctamente para la lista vacía, para elementos vacíos o cuando $IFS
no contenía espacio (los dos primeros problemas finalmente se solucionaron en versiones posteriores )
El shell Korn (en el que se basa la especificación POSIX) cambió ese comportamiento de varias maneras:
- La división IFS solo se realiza en el resultado de expansiones sin comillas (no en palabras literales como
edit
ofile.txt
en el ejemplo anterior)
$*
y $@
se unen con el primer carácter de $IFS
o espacio cuando $IFS
está vacío, excepto que para una cita "$@"
, esa unión no se cita como en el shell Bourne, y para una cita "$*"
cuando IFS
está vacía, los parámetros posicionales se agregan sin separador.
- se añadió soporte para las matrices, y con
${array[@]}
${array[*]}
reminiscencia de Bourne de $*
y $@
pero a partir de indice 0 en lugar de 1, y escasa (más como matrices asociativas) lo que significa $@
realmente no pueden ser tratados como una matriz de ksh (comparar con csh
/ rc
/ zsh
/ fish
/ yash
donde $argv
/ $*
son normales matrices).
- Los elementos vacíos se conservan.
"$@"
cuando $#
es 0 ahora se expande a nada en lugar de la cadena vacía, "$@"
funciona cuando $IFS
no contiene espacios, excepto cuando IFS
está vacío. Un $*
sin comillas sin comodines se expande a un argumento (donde los parámetros posicionales se unen con el espacio) cuando $IFS
está vacío.
ksh93 solucionó los pocos problemas restantes anteriores. En ksh93, $*
y se $@
expande a la lista de parámetros posicionales, separados independientemente del valor de $IFS
, y luego se divide + globbed + brace-expandido en contextos de lista, $*
unido con el primer byte (no carácter) de $IFS
, "$@"
en contextos de lista se expande a la lista de parámetros posicionales, independientemente del valor de $IFS
. En un contexto que no es de lista, como en var=$@
, $@
se une con espacio independientemente del valor de $IFS
.
bash
Las matrices están diseñadas después de las ksh. Las diferencias son:
- sin llave de expansión en la expansión sin comillas
- primer carácter de en
$IFS
lugar de por byte
- algunas diferencias de mayúsculas y minúsculas, como la expansión de
$*
cuando no se cita en un contexto sin lista cuando $IFS
está vacío.
Si bien la especificación POSIX solía ser bastante vaga, ahora más o menos especifica el comportamiento bash.
Es diferente de las matrices normales en ksh
o bash
en eso:
- Los índices comienzan en 1 en lugar de 0 (excepto en el
"${@:0}"
que incluye $0
(no es un parámetro posicional, y en funciones le da el nombre de la función o no dependiendo del shell y cómo se definió la función)).
- No puedes asignar elementos individualmente
- no es escaso, no puedes desarmar elementos individualmente
shift
puede ser usado.
En zsh
o yash
donde las matrices son matrices normales (no dispersas, los índices comienzan en uno como en todos los demás shells pero ksh / bash), $*
se trata como una matriz normal. zsh
tiene $argv
como un alias para ello (por compatibilidad con csh
). $*
es lo mismo que $argv
or ${argv[*]}
(argumentos unidos con el primer carácter de $IFS
pero aún separados en contextos de lista). Me "$@"
gusta "${argv[@]}"
o se "${*[@]}"}
somete al procesamiento especial de estilo Korn.