Ide dasarnya adalah bahwa VAR=VALUE some-command
set VAR
untuk VALUE
untuk pelaksanaan some-command
ketika some-command
adalah perintah eksternal, dan tidak mendapatkan lebih mewah dari itu. Jika Anda menggabungkan intuisi ini dengan beberapa pengetahuan tentang cara kerja shell, Anda harus menemukan jawaban yang tepat dalam banyak kasus. Referensi POSIX adalah "Perintah Sederhana" di bab "Bahasa Perintah Shell" .
Jika some-command
merupakan perintah eksternal , VAR=VALUE some-command
sama dengan env VAR=VALUE some-command
. VAR
diekspor di lingkungan some-command
, dan nilainya (atau kurangnya nilai) di shell tidak berubah.
Jika some-command
adalah fungsi , maka VAR=VALUE some-command
setara dengan VAR=VALUE; some-command
, yaitu sisa-sisa tugas di tempat setelah fungsi telah kembali, dan variabel tersebut tidak diekspor ke lingkungan. Alasan untuk itu berkaitan dengan desain shell Bourne (dan kemudian dengan kompatibilitas ke belakang): ia tidak memiliki fasilitas untuk menyimpan dan mengembalikan nilai variabel di sekitar pelaksanaan fungsi. Tidak mengekspor variabel masuk akal karena fungsi dijalankan di shell itu sendiri. Namun, ksh (termasuk ATT ksh93 dan pdksh / mksh), bash dan zsh mengimplementasikan perilaku yang lebih bermanfaat di mana VAR
hanya diatur selama eksekusi fungsi (itu juga diekspor). Dalam ksh , ini dilakukan jika fungsi didefinisikan dengan sintaks kshfunction NAME …
, tidak jika itu didefinisikan dengan sintaks standar NAME ()
. Dalam bash , ini dilakukan hanya dalam mode bash, bukan dalam mode POSIX (saat dijalankan dengan POSIXLY_CORRECT=1
). Di zsh , ini dilakukan jika posix_builtins
opsi tidak disetel; opsi ini tidak diatur secara default tetapi dihidupkan oleh emulate sh
atau emulate ksh
.
Jika some-command
builtin, perilaku tergantung pada tipe builtin. Builtin khusus berperilaku seperti fungsi. Built-in khusus adalah yang harus diimplementasikan di dalam shell karena mereka mempengaruhi shell negara (misalnya break
memengaruhi aliran kontrol, cd
memengaruhi direktori saat ini, set
memengaruhi parameter dan opsi posisi ...). Builtin lainnya hanya built-in untuk kinerja dan kenyamanan (kebanyakan - misalnya fitur bash printf -v
hanya dapat diimplementasikan oleh builtin), dan mereka berperilaku seperti perintah eksternal.
Penugasan berlangsung setelah ekspansi alias, jadi jika some-command
merupakan alias , perluas terlebih dahulu untuk menemukan apa yang terjadi.
Perhatikan bahwa dalam semua kasus, penugasan dilakukan setelah baris perintah diuraikan, termasuk substitusi variabel apa pun pada baris perintah itu sendiri. Jadi var=a; var=b echo $var
cetak a
, karena $var
dievaluasi sebelum penugasan berlangsung. Dan dengan demikian IFS=. printf "%s\n" $var
menggunakan nilai lama IFS
untuk membagi $var
.
Saya sudah membahas semua jenis perintah, tetapi ada satu kasus lagi: ketika tidak ada perintah untuk dieksekusi , yaitu jika perintah hanya terdiri dari tugas (dan mungkin pengalihan). Dalam hal itu, penugasan tetap di tempatnya . VAR=VALUE OTHERVAR=OTHERVALUE
setara dengan VAR=VALUE; OTHERVAR=OTHERVALUE
. Jadi setelah IFS=. arr=($var)
, IFS
tetap diatur ke .
. Karena Anda dapat menggunakan $IFS
dalam penugasan arr
dengan harapan bahwa itu sudah memiliki nilai baru, masuk akal bahwa nilai baru IFS
digunakan untuk ekspansi $var
.
Singkatnya, Anda dapat menggunakan hanya IFS
untuk pemisahan bidang sementara :
- dengan memulai shell baru atau subkulit (mis.
third=$(IFS=.; set -f; set -- $var; echo "$3")
adalah cara yang rumit untuk dilakukan third=${var#*.*.}
kecuali bahwa mereka berperilaku berbeda ketika nilai var
mengandung kurang dari dua .
karakter);
- di ksh, dengan
IFS=. some-function
mana some-function
didefinisikan dengan sintaks ksh function some-function …
;
- dalam bash dan zsh, dengan
IFS=. some-function
selama mereka beroperasi dalam mode asli yang bertentangan dengan mode kompatibilitas.
IFS
tetap diatur ke.
" Eek. Setelah membaca bagian pertama, itu masuk akal, tetapi sebelum saya memposting Q ini, saya tidak akan mengharapkan itu.Jawaban @Gilles benar-benar hebat, ia menjelaskan (secara terperinci) masalah yang kompleks.
Namun, saya yakin itulah jawaban mengapa perintah ini:
berfungsi sebagaimana adanya adalah gagasan sederhana bahwa seluruh baris perintah diuraikan sebelum dieksekusi. Dan setiap "kata" diproses satu kali oleh shell.
The tugas, seperti
IFS=.
, tertunda (langkah 4 adalah yang terakhir):sampai sebelum perintah dieksekusi dan semua ekspansi dalam argumen diproses terlebih dahulu untuk membangun baris yang dapat dieksekusi ini:
Nilai
$var
diperluas dengan IFS "lama"a.b.c
sebelum perintahprintf
diberikan argumen"%s\n"
dana.b.c
.Eval
Satu tingkat keterlambatan dapat diperkenalkan oleh
eval
:Baris diurai (pertama kali) dan 'IFS =.' diatur ke lingkungan karena ini:
Kemudian diuraikan lagi untuk ini:
Dan dieksekusi untuk ini:
Nilai
$var
(abc) dibagi dengan nilai IFS digunakan:.
.Lingkungan Hidup
Bagian yang rumit dan rumit adalah apa yang valid di lingkungan kapan !!!
Itu dijelaskan dengan sangat baik di bagian pertama jawaban Gilles.
Dengan detail tambahan.
Ketika perintah ini dijalankan:
Nilai IFS dipertahankan di lingkungan saat ini, ya:
IFS untuk satu pernyataan.
Tapi itu bisa dihindari: Mengatur IFS untuk satu pernyataan
sumber
Pertanyaan Anda tentang
adalah kasus sudut.
Ini karena
macro expansion
dalam perintah terjadi sebelum variabel shellIFS=.
diatur.Dengan kata lain: ketika
$var
diperluas, nilai sebelumnyaIFS
aktif, kemudianIFS
diatur ke'.'
.sumber