Cuál es la diferencia entre estos dos:
cnt=1 head -n $((++cnt)) /etc/passwd >/dev/null echo $cnt # prints 2y
cnt=1 date >$((++cnt)).txt # creates file "2.txt" echo $cnt # prints 1Mi pregunta es por qué en el segundo ejemplo se imprime 1. Nota:
cnt=1 (cnt=5) echo $cnt # prints 1Sé por qué esto imprimirá 1. ¿La redirección también se ejecuta en una subcapa? En caso afirmativo, ¿dónde se describe?
prueba esto
let cnt=1 echo `date` > "$((++cnt))".txt echo $cnt(editando mi respuesta) @alaniwi señaló que strace muestra claramente un clon. Y estoy de acuerdo con PP en que no indica que haya una subcapa y, después de revisar la documentación, no encontré una referencia directa para ella.
EDITAR : sustitución de comandos, sustituciones de procesos bifurcan una subcapa. Quiero citar lo siguiente de https://www.gnu.org/software/bash/manual/bash.html#Command-Execution-Environment
Command substitution, commands grouped with parentheses, and asynchronous commands are invoked in a subshell environment ...Esto puede contener algunas respuestas más:
https://www.gnu.org/software/bash/manual/bash.html (busque la sustitución de comandos)
No tengo una cita concreta de por qué existe este comportamiento, pero saliendo de las notas en SC2257 * hay algunos puntos interesantes a tener en cuenta en el manual.
Cuando se va a ejecutar un comando simple que no sea una función incorporada o de shell , 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 de que se invoque 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 Revisé la guía zsh pero tampoco encontré una mención exacta de este comportamiento.
No hace falta decir que 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 ocurren las 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:805Cuando 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 enlazadas después de la bifurcación no se reflejarán en el caparazón 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 [ árbol de navegación])