nilai sementara skrip bash pada perintah


11

Seperti perintah di bawah ini,

if true; then
   IFS=":" read a b c d e f <<< "$test"

Buku itu mengatakan ketika perintah penetapan nilai ( IFS ":") digunakan sebelum perintah utama ( read a b c d e f <<< "$value"), nilainya efektif pada perintah utama sementara. Jadi, readperintahnya menggunakan pembatas :.

Tapi, seperti perintah ini,

if true; then
   HOME="hello" echo "$HOME"

Pesan gema bukan halo. Apa arti sebenarnya dari perintah di atas?

Jawaban:


5

Ini muncul ke pertanyaan tentang bagaimana evaluasi bekerja. Kedua contoh bekerja dengan cara yang sama, masalahnya terjadi karena bagaimana shell (bash, di sini) memperluas variabel.

Saat Anda menulis perintah ini:

HOME="foo" echo $HOME

Ini $HOMEdiperluas sebelum perintah dijalankan . Oleh karena itu, diperluas ke nilai asli dan bukan yang baru yang telah Anda atur untuk perintah. The HOMEvariabel memang telah berubah dalam lingkungan bahwa echoperintah berjalan di, namun, Anda mencetak $HOMEdari orangtua.

Untuk menggambarkan, pertimbangkan ini:

$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon

Seperti yang Anda lihat di atas, perintah pertama mencetak nilai sementara yang diubah HOMEdan yang kedua mencetak yang asli, menunjukkan bahwa variabel hanya diubah sementara. Karena bash -c ...perintah dilampirkan dalam tanda kutip tunggal ( ' ') alih-alih tanda kutip ganda ( " "), variabel tidak diperluas dan diteruskan apa adanya ke proses bash baru. Proses baru ini kemudian mengembangkannya dan mencetak nilai baru yang telah ditetapkan. Anda dapat melihat ini terjadi jika Anda menggunakan set -x:

$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello         
+ echo hello
hello

Seperti yang Anda lihat di atas, variabel $HOME tidak pernah dilewatkan ke echo. Hanya melihat nilainya yang diperluas. Dibandingkan dengan:

$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello

Di sini, karena tanda kutip tunggal, variabel dan bukan nilainya diteruskan ke proses baru.


7

Ketika shell mem-parsing sebuah baris, itu akan mengubah tokenize menjadi kata-kata, melakukan berbagai ekspansi (dalam urutan) pada kata-kata, kemudian jalankan perintah.

Seharusnya test=1:2:3:4:5:6

Mari kita lihat perintah ini: IFS=":" read a b c d e f <<< "$test"

Setelah tokenizing, dan terjadi ekspansi parameter :IFS=":" read a b c d e f <<< "1:2:3:4:5:6"

Shell akan mengatur variabel IFS untuk durasi perintah read, dan readtahu bagaimana menerapkan $ IFS ke inputnya , dan memberikan nilai pada nama-nama variabel.

Perintah ini memiliki cerita yang serupa, tetapi hasilnya berbeda: HOME="hello" echo "$HOME"

Karena ekspansi parameter terjadi sebelum perintah dimulai, shell memiliki:

HOME="hello" echo "/home/username"

Dan kemudian, selama eksekusi dari perintah echo, nilai baru $ HOME tidak digunakan sama sekali.

Untuk mencapai apa yang Anda coba lakukan, pilih salah satunya

# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'

atau

# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")

tapi jangan memilih yang pertama.


Mungkin lebih baik memilih yang pertama. Setidaknya ini secara signifikan lebih cepat. Ketika eval adalah jawabannya, Anda kadang-kadang mungkin mengajukan pertanyaan yang salah. Tetapi jika seseorang harus melakukan itu untuk beberapa alasan, mengubah jawaban itu tidak membuat pertanyaan itu sendiri tidak salah. Solusi lain adalah membungkusnya dalam suatu fungsi dan penggunaan local.
user23013

Mengapa evalsolusinya harus dihindari?
DarkHeart

Jika Anda tidak benar-benar mengontrol input, Anda harus sangat berhati-hati tentang kode yang Anda izinkan orang lain untuk menyuntikkan ke dalam program Anda.
glenn jackman

-1

Ada dua cakupan: variabel lingkungan dan variabel lokal. Variabel lingkungan valid untuk setiap proses (lihat setenv, getenv), sedangkan variabel lokal hanya aktif dalam sesi shell ini. (Ini bukan perbedaan yang jelas ...)

Tersirat env(seperti dalam contoh Anda) memodifikasi lingkungan, sementara echo ...menggunakan yang lokal - jadi envtidak berpengaruh.

Untuk memodifikasi variabel lokal gunakan, katakan,

( HOME="foo" ; echo "$HOME" )

Di sini tanda kurung menentukan ruang lingkup penugasan ini.


1
Ini tidak ada hubungannya dengan cakupan variabel, masalahnya adalah bahwa variabel sedang diperluas sebelum diteruskan ke shell anak.
terdon
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.