Ich habe kein konkretes Zitat für warum Dieses Verhalten existiert, aber abgesehen von den Anmerkungen in SC2257* gibt es einige interessante Punkte, die im Handbuch zu beachten sind.
Wenn ein einfacher Befehl anders als eine eingebaute oder Shell-Funktion ist ausgeführt werden soll, wird es in einer separaten Ausführungsumgebung aufgerufen
§3.7.3 Befehlsausführungsumgebung
Dies spiegelt die Anmerkungen von SC2257 wider, obwohl unklar ist, in welcher Umgebung der Wert der Umleitung ausgewertet wird. §3.1.1 Shell Operation scheint jedoch zu sagen, dass die Umleitung vorher erfolgt Diese Ausführungs-(Unter-)Umgebung wird aufgerufen:
Grundsätzlich macht die Shell Folgendes:
...
- Führt die verschiedenen Shell-Erweiterungen durch....
- Führt alle erforderlichen Umleitungen durch und entfernt die Umleitungsoperatoren und ihre Operanden aus der Argumentliste.
- Führt den Befehl aus.
Wir können sehen, dass dies nicht auf arithmetische Erweiterungen beschränkt ist, sondern auch auf andere zustandsändernde Erweiterungen wie :=
:
$ bash -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=
$ bash -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow
Interessanterweise scheint dies keine (wohldefinierte) Subshell-Umgebung zu sein, weil BASH_SUBSHELL
bleibt auf 0
gesetzt :
$ date >"${word:=$BASH_SUBSHELL}.txt"; ls
0.txt
Wir können auch einige andere Shells überprüfen und sehen, dass zsh
hat das gleiche Verhalten, obwohl dash
nicht:
$ 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
Ich habe den zsh
überflogen Guide, fand dort aber auch keine genaue Erwähnung dieses Verhaltens.
Unnötig zu sagen , scheint dies kein gut dokumentiertes Verhalten zu sein, daher ist es ein Glück, dass ShellCheck helfen kann, es zu erkennen. Es scheint jedoch ein langjähriges Verhalten zu sein, es ist in Bash 3, 4 und 5 reproduzierbar.
* Leider verlinkt der Commit, der SC2257 hinzugefügt hat, nicht auf ein Problem oder einen anderen weiteren Kontext.
Der Rat von Shellcheck ist vernünftig; manchmal werden Umleitungen in Subshells durchgeführt. Der springende Punkt bei diesem Verhalten ist jedoch wann Erweiterungen auftreten:
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
Wenn execute_disk_command() aufgerufen wird, verzweigt es sich und führt dann date(1) aus. Nach dem fork() und vor dem execve() werden Umleitungen und zusätzliche Erweiterungen durchgeführt (über do_redirections()). Erweiterte und gebundene Post-Fork-Variablen spiegeln sich nicht in der übergeordneten Shell wider.
Aus Sicht von BASH ist dies jedoch eher ein einfacher Befehl als ein Subshell-Befehl. Dies ist eine implizite Subshell.
Siehe execute_disk_command() in 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.
(Verweise aus Commit 9e49d343e3cd7e20dad1b86ebfb764e8027596a7 [Browse Tree])