No tengo una cita concreta para por qué este comportamiento existe, pero saliendo de las notas en SC2257* hay algunos puntos interesantes a tener en cuenta en el manual.
Cuando un comando simple que no sea una función incorporada o de shell se va a ejecutar, se invoca en un entorno de ejecución separado
§3.7.3 Entorno de ejecución de comandos
Esto refleja lo que señala SC2257, aunque no está claro en qué entorno se evalúa el valor de la redirección. Sin embargo, §3.1.1 Operación Shell parece decir que la redirección ocurre antes se invoca este (sub)entorno de ejecución:
Básicamente, el shell hace lo siguiente:
...
- Realiza las diversas expansiones de shell....
- Realiza las redirecciones necesarias y elimina los operadores de redirección y sus operandos de la lista de argumentos.
- Ejecuta el comando.
Podemos ver que esto no se limita a las expansiones aritméticas sino también a otras expansiones que cambian de estado como :=
:
$ bash -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=
$ bash -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow
Curiosamente, esto no parece ser un entorno de subcapa (bien definido), porque BASH_SUBSHELL
permanece establecido en 0
:
$ date >"${word:=$BASH_SUBSHELL}.txt"; ls
0.txt
También podemos verificar algunos otros shells y ver que zsh
tiene el mismo comportamiento, aunque dash
no:
$ zsh -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=
$ zsh -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow
$ dash -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=wow
$ dash -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow
Leí el zsh
pero tampoco encontré una mención exacta de este comportamiento allí.
No hace falta decir , este no parece ser un comportamiento bien documentado, por lo que es una suerte que ShellCheck pueda ayudar a detectarlo. Sin embargo, parece ser un comportamiento de larga data, es reproducible en Bash 3, 4 y 5.
* Desafortunadamente, la confirmación que agregó SC2257 no se vincula a un problema ni a ningún otro contexto adicional.
El consejo de Shellcheck es sensato; a veces, las redirecciones se realizan en subcapas. Sin embargo, el quid de este comportamiento es cuando se producen expansiones:
bind_int_variable variables.c:3410 cnt = 2, late binding
expr_bind_variable expr.c:336
exp0 expr.c:1040
exp1 expr.c:1007
exppower expr.c:962
expmuldiv expr.c:887
exp3 expr.c:861
expshift expr.c:837
exp4 expr.c:807
exp5 expr.c:785
expband expr.c:767
expbxor expr.c:748
expbor expr.c:729
expland expr.c:702
explor expr.c:674
expcond expr.c:627
expassign expr.c:512
expcomma expr.c:492
subexpr expr.c:474
evalexp expr.c:439
param_expand subst.c:9498 parameter expansion, including arith subst
expand_word_internal subst.c:9990
shell_expand_word_list subst.c:11335
expand_word_list_internal subst.c:11459
expand_words_no_vars subst.c:10988
redirection_expand redir.c:287 expansions post-fork()
do_redirection_internal redir.c:844
do_redirections redir.c:230 redirections are done in child process
execute_disk_command execute_cmd.c:5418 fork to run date(1)
execute_simple_command execute_cmd.c:4547
execute_command_internal execute_cmd.c:842
execute_command execute_cmd.c:394
reader_loop eval.c:175
main shell.c:805
Cuando se llama a execute_disk_command(), se bifurca y luego ejecuta date(1). Después de fork() y antes de execve(), se realizan redirecciones y expansiones adicionales (a través de do_redirections()). Las variables expandidas y vinculadas después de la bifurcación no se reflejarán en el shell principal.
Sin embargo, desde la perspectiva de BASH, este es solo un comando simple en lugar de un comando de subcapa. Esta es una subcapa implícita.
Ver execute_disk_command() en execute_cmd.c
Execute a simple command that is hopefully defined in a disk file
somewhere.
1) fork ()
2) connect pipes
3) look up the command
4) do redirections
5) execve ()
6) If the execve failed, see if the file has executable mode set.
If so, and it isn't a directory, then execute its contents as
a shell script.
(referencias tomadas de commit 9e49d343e3cd7e20dad1b86ebfb764e8027596a7 [navegar árbol])