Mengapa $ RANDOM tidak termasuk dalam output 'env'?

23

Saya tahu envadalah perintah shell, dapat digunakan untuk mencetak daftar variabel lingkungan saat ini. Dan sejauh yang saya mengerti, RANDOMjuga merupakan variabel lingkungan.

Jadi mengapa, ketika saya meluncurkan envdi Linux, apakah hasilnya tidak termasuk RANDOM?

mcmxciv
sumber
4
envbukan perintah shell karena biasanya tidak dibangun ke dalam shell.
schily
@schily BTW untuk Bash, declare -xadalah setara dengan builtin shell.
wjandrea

Jawaban:

42

RANDOMbukan variabel lingkungan. Ini adalah variabel shell yang dikelola oleh beberapa shell. Biasanya tidak diekspor secara default. Inilah sebabnya mengapa itu tidak muncul di output env.

Setelah digunakan setidaknya sekali, itu akan muncul di output set, yang, dengan sendirinya, mencantumkan variabel shell (dan fungsi) dan nilainya dalam sesi shell saat ini. Perilaku ini tergantung pada shell dan digunakan pdkshpada OpenBSD, RANDOMakan terdaftar setbahkan jika sebelumnya tidak digunakan.


Sisa dari jawaban ini menyangkut apa yang bisa diharapkan terjadi jika RANDOMdiekspor (yaitu diubah menjadi variabel lingkungan).

Mengekspornya export RANDOMakan menjadikannya variabel lingkungan tetapi penggunaannya akan sangat terbatas karena nilainya dalam proses anak akan "acak tetapi statis" (artinya itu akan menjadi angka acak yang tidak berubah). Perilaku yang tepat berbeda antara shell.

Saya menggunakan pdkshOpenBSD pada contoh di bawah ini dan saya mendapatkan nilai acak baru di setiap proses awk(tetapi nilai yang sama setiap kali dalam waktu yang samaawk contoh yang ). Menggunakan bash, saya akan mendapatkan nilai acak yang persis sama di semua doa awk.

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
25444 25444

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
30906 30906

Dalam bash, nilai yang diekspor RANDOMakan tetap statis terlepas dari penggunaan RANDOMdi shell (di mana setiap penggunaan $RANDOMmasih akan memberikan nilai baru).

Ini karena setiap referensi ke variabel shell RANDOM di bashmembuat shell mengakses get_random()fungsi internal untuk memberikan variabel nilai acak baru, tetapi shell tidak memperbarui variabel lingkungan RANDOM . Hal ini mirip dalam perilaku seperti dengan dinamis lainnya bashvariabel, seperti LINENO, SECONDS, BASHPIDdll

Untuk memperbarui variabel lingkungan RANDOMdi bash, Anda harus menetapkan nilai variabel shellRANDOM dan -ekspor ulang itu:

export RANDOM="$RANDOM"

Tidak jelas bagi saya apakah ini akan memiliki efek samping tambahan dari penyemaian ulang nomor acak generator di bashatau tidak (tapi tebakan yang berpendidikan adalah bahwa itu tidak).

Kusalananda
sumber
1
Apakah RANDOMbahkan memiliki nilai sebelum Anda menggunakannya? Saya selalu menganggap itu hanya dihuni ketika dipanggil.
terdon
1
Bukan, manual bash menyebutkannya.
terdon
1
Meskipun jika Anda melakukan bahkan export RANDOMatau declare -p RANDOM, itu muncul, jadi saya tidak yakin apakah ada gunanya itu tidak ada sebelum direferensikan ...
ilkkachu
1
"Nilainya dalam proses anak akan acak, tetapi statis." Jika statis, tidak acak , apakah itu tiga byte atau enam belas.
l0b0
3
@ l0b0 Ini akan acak dalam arti bahwa Anda tidak akan dapat memprediksinya. Jelas, setelah Anda membacanya, itu tidak lagi acak karena tidak akan berubah (kecuali mengekspor kembali seperti yang saya tunjukkan, dalam hal ini variabel lingkungan akan mendapatkan nilai acak baru). Inilah sebabnya saya mengatakan itu acak tetapi statis. Saya sudah mengklarifikasi hal ini dalam teks sekarang.
Kusalananda
16

Tidak semua variabel yang diatur dalam sesi shell Anda adalah variabel lingkungan. "Variabel lingkungan" hanya merujuk ke variabel yang telah diekspor ke lingkungan menggunakan exportbuiltin. The envperintah saja mencetak seperti lingkungan variabel. Sebagai contoh:

$ foo="bar"
$ env | grep foo ## returns nothing
$ export foo
$ env | grep foo ## now, env will print it
foo=bar

Jika Anda ingin melihat semua variabel diatur dalam sesi Anda, terlepas dari apakah mereka telah diekspor, Anda dapat menggunakan set:

$ set | grep foo=
foo=bar

The setbuiltin juga kembali fungsi, sehingga untuk melihat variabel saja, Anda dapat menggunakan:

set | grep  '^[^[:space:]]*='

Akhirnya, RANDOMvariabel khusus karena hanya diberi nilai saat Anda referensi. Ini disebutkan dalam bash (1) :

RANDOM

    Setiap kali parameter ini direferensikan, bilangan bulat acak antara 0 dan 32767 dihasilkan. Urutan angka acak dapat diinisialisasi dengan menetapkan nilai RANDOM. JikaRANDOM tidak disetel, ini akan kehilangan properti khusus, meskipun kemudian diatur ulang.

Jadi, bahkan jika itu adalah variabel lingkungan seperti yang Anda pikirkan, itu tidak akan ditampilkan envkarena tidak akan ditetapkan sampai pertama kali Anda menyebutnya. Itu juga mengapa itu tidak ditampilkan di set:

$ set | grep RAN   ## returns nothing, RANDOM is unset
$ echo "$RANDOM"   ## this will assign a value to RANDOM
1234
$ set | grep RAN   ## so now it will also appear in the output of set 
RANDOM=1234
terdon
sumber
Itu penemuan yang menarik set | grep RAN. Saya tidak akan menduganya. FWIW, saya percaya bahwa itu tidak dapat diprediksi oleh dokumentasi.
G-Man Mengatakan 'Reinstate Monica'
1
PS Selamat sudah mencapai 120.000. (Saya kira saya baru saja menempatkan Anda.)
G-Man Mengatakan 'Reinstate Monica'
4

Kebanyakan shell akan memiliki sejumlah variabel lain yang ditetapkan atau digunakan oleh shell yang tidak diekspor ke proses anak secara default.

Di Bash, ada beberapa yang jelas spesifik Bash:

$ echo "${!BASH*}"
BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION
$ echo $BASH_VERSION
4.4.12(1)-release
$ env|grep -c BASH
0

Lalu ada lagi yang standar seperti OPTINDdan OPTERR(digunakan oleh getopts), dan PS2,PS3 (permintaan sekunder) dan bahkan variabel "ajaib" lainnya: SECONDS(menunjukkan waktu dalam detik sejak shell dimulai)

Di Bash, Anda dapat melihat semua variabel dan status ekspornya declare -p. Yang ditandai dengan -xdiekspor, yang tanpa xtidak. (Beberapa akan memiliki flag lain seperti iuntuk integer ataur hanya-baca.)

Di Zsh atau ksh93, Anda dapat menggunakan typeset -p, meskipun Zsh menandai variabel yang diekspor dengan mengubah typesetke exportdalam output, alih-alih menggunakan flag. exportdengan sendirinya juga akan menunjukkan semua variabel yang diekspor, tapi itu tentang hasil yang sama Anda dapatkan dengan menjalankan env.

ilkkachu
sumber
2

Jika Anda Google untuk ini, dokumen menyatakan sebagai berikut:

$RANDOMadalah fungsi Bash internal (bukan konstanta) yang mengembalikan integer pseudorandom [1] dalam kisaran 0 - 32767. Fungsi ini seharusnya tidak digunakan untuk menghasilkan kunci enkripsi.

Jika Anda menggunakan, straceAnda dapat melihat bahwa $RANDOM"variabel" diteruskan langsung ke perintah seolah-olah itu adalah variabel shell biasa atau variabel lingkungan, tapi itu hanya fungsi internal yang dibangun ke dalam shell, Bash, yang melakukan ekspansi.

$ strace -t echo "random value: $RANDOM"
04:37:58 execve("/bin/echo", ["echo", "random value: 30795"], [/* 27 vars */]) = 0
04:37:58 brk(NULL)                      = 0x19c1000
04:37:58 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9841351000
...

vs variabel reguler ini:

$ strace -t echo "random value: $SOMEVAR"
04:40:19 execve("/bin/echo", ["echo", "random value: helloworld"], [/* 27 vars */]) = 0
04:40:19 brk(NULL)                      = 0x154b000
04:40:19 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f659d2eb000
...

Variabel tidak diteruskan sebagai referensi.

Referensi

slm
sumber
1
baik, bukankah itu melewati nilai diperluas $RANDOMatau $SOMEVARmelalui argumen baris perintah, dan bukan sebagai variabel lingkungan? Anda harus exportmelewati keduanya melalui lingkungan.
ilkkachu
Tidak, itu tidak akan membuat perbedaan. Shell mengekspansi mereka. Cara saya menunjukkan pada dasarnya menyoroti fakta bahwa shell sedang melakukan ekspansi.
slm
2
The straceOutput tampaknya tidak menangkap fungsi internal yang dijalankan oleh shell. Dalam kedua kasus, variabel telah diperluas di baris pertama strace. Saya tidak mengerti apa yang Anda tunjukkan. Apa yang saya lewatkan?
terdon
Menunjukkan bahwa $RANDOMekspansi dilakukan secara internal ke shell. Ini pada dasarnya konfirmasi bahwa shell menentukan nilai, dan tidak meneruskan referensi ke variabel. Shell saat memperluas baris perintah untuk mengeksekusi parses $RANDOMdan meneruskan formulir yang diperluas echo.
slm
2
Jadi, tidak seperti variabel lingkungan .
Toby Speight