La idea básica es que los VAR=VALUE some-command
conjuntos VAR
a VALUE
la ejecución de some-command
cuando some-command
es un comando externo, y que no puede ser más elegante que eso. Si combina esta intuición con algún conocimiento de cómo funciona un shell, debe encontrar la respuesta correcta en la mayoría de los casos. La referencia POSIX es "Comandos simples" en el capítulo "Lenguaje de comandos de Shell" .
Si some-command
es un comando externo , VAR=VALUE some-command
es equivalente a env VAR=VALUE some-command
. VAR
se exporta en el entorno de some-command
, y su valor (o falta de valor) en el shell no cambia.
Si some-command
es una función , entonces VAR=VALUE some-command
es equivalente a VAR=VALUE; some-command
, es decir, la asignación permanece en su lugar después de que la función ha regresado y la variable no se exporta al entorno. La razón de esto tiene que ver con el diseño del shell Bourne (y posteriormente con la compatibilidad con versiones anteriores): no tenía facilidad para guardar y restaurar valores variables en torno a la ejecución de una función. No exportar la variable tiene sentido ya que una función se ejecuta en el propio shell. Sin embargo, ksh (incluidos ATT ksh93 y pdksh / mksh), bash y zsh implementan el comportamiento más útil donde VAR
se establece solo durante la ejecución de la función (también se exporta). En ksh , esto se hace si la función se define con la sintaxis kshfunction NAME …
, no si se define con la sintaxis estándar NAME ()
. En bash , esto se hace solo en modo bash, no en modo POSIX (cuando se ejecuta con POSIXLY_CORRECT=1
). En zsh , esto se hace si la posix_builtins
opción no está configurada; esta opción no está configurada de manera predeterminada pero está activada por emulate sh
o emulate ksh
.
Si se some-command
trata de una construcción, el comportamiento depende del tipo de construcción. Los componentes especiales especiales se comportan como funciones. Las incorporaciones especiales son las que deben implementarse dentro del shell porque afectan el shell de estado (por ejemplo break
, cd
afecta el flujo de control, afecta el directorio actual, set
afecta los parámetros de posición y las opciones ...). Otras funciones incorporadas están integradas solo por rendimiento y conveniencia (principalmente, por ejemplo, la función bash printf -v
solo puede implementarse mediante una función integrada), y se comportan como un comando externo.
La asignación se lleva a cabo después de la expansión del alias, por lo que si some-command
es un alias , amplíelo primero para encontrar qué sucede.
Tenga en cuenta que en todos los casos, la asignación se realiza después de analizar la línea de comando, incluida cualquier sustitución de variable en la línea de comando. Entonces var=a; var=b echo $var
imprime a
, porque $var
se evalúa antes de que se realice la asignación. Y así IFS=. printf "%s\n" $var
usa el IFS
valor anterior para dividir $var
.
He cubierto todos los tipos de comandos, pero hay un caso más: cuando no hay un comando para ejecutar , es decir, si el comando consiste solo en asignaciones (y posiblemente redireccionamientos). En ese caso, la asignación permanece en su lugar . VAR=VALUE OTHERVAR=OTHERVALUE
es equivalente a VAR=VALUE; OTHERVAR=OTHERVALUE
. Entonces IFS=. arr=($var)
, después , IFS
permanece establecido en .
. Como puede usar $IFS
en la asignación arr
con la expectativa de que ya tiene su nuevo valor, tiene sentido que el nuevo valor de IFS
se use para la expansión de $var
.
En resumen, puede usar solo IFS
para la división temporal de campos:
- iniciando un nuevo shell o un subshell (por ejemplo,
third=$(IFS=.; set -f; set -- $var; echo "$3")
es una forma complicada de hacerlo, third=${var#*.*.}
excepto que se comportan de manera diferente cuando el valor de var
contiene menos de dos .
caracteres);
- en ksh, con
IFS=. some-function
donde some-function
se define con la sintaxis ksh function some-function …
;
- en bash y zsh,
IFS=. some-function
siempre y cuando estén operando en modo nativo en oposición al modo de compatibilidad.
IFS
permanece establecido en.
" Eek. Después de leer la primera parte, eso tiene sentido, pero antes de publicar esta Q, no hubiera esperado eso.La respuesta de @Gilles es realmente genial, explica (en detalle) un tema complejo.
Sin embargo, creo que la respuesta a por qué este comando:
funciona como lo hace la simple idea de que toda la línea de comando se analiza antes de ejecutarse. Y que cada "palabra" es procesada una vez por el shell.
Las tareas, como
IFS=.
, se retrasan (el paso 4 es el último):hasta justo antes de que se ejecute el comando y todas las expansiones en los argumentos se procesen primero para construir esta línea ejecutable:
El valor de
$var
se expande con el IFS "anterior"a.b.c
antes de que el comandoprintf
reciba los argumentos"%s\n"
ya.b.c
.Eval
Un nivel de retraso puede ser introducido por
eval
:La línea se analiza (primera vez) y 'IFS =.' se establece en el entorno como este:
Luego se analiza nuevamente esto:
Y ejecutado a esto:
El valor de
$var
(abc) se divide por el valor de IFS en uso:.
.Ambiente
La parte compleja y complicada es lo que es válido en el entorno cuando !!!
Eso se explica muy bien en la primera parte de la respuesta de Gilles.
Con un detalle adicional.
Cuando se ejecuta este comando:
El valor de IFS se conserva en el entorno actual, sí:
IFS para una sola declaración.
Pero podría evitarse: configurar IFS para una sola declaración
fuente
Su pregunta sobre
Es un caso de esquina.
Esto se debe a que
macro expansion
en el comando ocurre antes de queIFS=.
se establezca la variable de shell .En otras palabras: cuando
$var
se expande, elIFS
valor anterior está activo, luegoIFS
se establece en'.'
.fuente