Saya tidak memiliki kutipan konkret untuk mengapa perilaku ini memang ada, tetapi mencatat di SC2257* ada beberapa poin menarik untuk diperhatikan di manual.
Saat perintah sederhana selain fungsi bawaan atau shell akan dieksekusi, itu dipanggil di lingkungan eksekusi yang terpisah
§3.7.3 Lingkungan Eksekusi Perintah
Ini mencerminkan apa yang dicatat SC2257, meskipun tidak jelas tentang di lingkungan mana nilai pengalihan dievaluasi. Namun §3.1.1 Operasi Shell sepertinya mengatakan bahwa pengalihan terjadi sebelum lingkungan (sub)eksekusi ini dipanggil:
Pada dasarnya, shell melakukan hal berikut:
...
- Melakukan berbagai perluasan shell....
- Melakukan pengalihan yang diperlukan dan menghapus operator pengalihan dan operannya dari daftar argumen.
- Jalankan perintah.
Kita dapat melihat bahwa ini tidak terbatas pada perluasan aritmatika tetapi juga perluasan perubahan status lainnya seperti :=
:
$ bash -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=
$ bash -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow
Menariknya, ini tampaknya bukan lingkungan subkulit (terdefinisi dengan baik), karena BASH_SUBSHELL
tetap disetel ke 0
:
$ date >"${word:=$BASH_SUBSHELL}.txt"; ls
0.txt
Kami juga dapat memeriksa beberapa shell lain, dan melihat zsh
itu memiliki perilaku yang sama, meskipun dash
tidak:
$ 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
Saya membaca sekilas zsh
panduan tetapi tidak menemukan penyebutan yang tepat tentang perilaku ini di sana.
Tak perlu dikatakan , ini tampaknya bukan perilaku yang terdokumentasi dengan baik, jadi untungnya ShellCheck dapat membantu menangkapnya. Namun tampaknya itu adalah perilaku lama, dapat direproduksi di Bash 3, 4, dan 5.
* Sayangnya komit yang menambahkan SC2257 tidak tertaut ke Masalah atau konteks lebih lanjut lainnya.
Nasihat Shellcheck masuk akal; terkadang pengalihan dilakukan dalam subkulit. Namun, inti dari perilaku ini adalah kapan perluasan terjadi:
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
Ketika execution_disk_command() dipanggil, ia bercabang dan kemudian mengeksekusi tanggal(1). Setelah fork() dan sebelum execve(), pengalihan dan perluasan tambahan dilakukan (melalui do_redirections()). Variabel yang diperluas dan diikat post-fork tidak akan tercermin di shell induk.
Namun, dari perspektif BASH, ini hanyalah perintah sederhana daripada perintah subkulit. Ini adalah subkulit implisit.
Lihat execution_disk_command() di execution_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.
(referensi diambil dari komit 9e49d343e3cd7e20dad1b86ebfb764e8027596a7 [browse tree])