ฉันรู้ว่าenv
เป็นคำสั่งเชลล์มันสามารถใช้ในการพิมพ์รายการของตัวแปรสภาพแวดล้อมปัจจุบัน และเท่าที่ฉันเข้าใจRANDOM
ก็เป็นตัวแปรสภาพแวดล้อม
ดังนั้นทำไมเมื่อฉันเปิดใช้งานenv
บน Linux ผลลัพธ์ไม่รวมRANDOM
?
declare -x
เทียบเท่ากับเชลล์ในตัว
ฉันรู้ว่าenv
เป็นคำสั่งเชลล์มันสามารถใช้ในการพิมพ์รายการของตัวแปรสภาพแวดล้อมปัจจุบัน และเท่าที่ฉันเข้าใจRANDOM
ก็เป็นตัวแปรสภาพแวดล้อม
ดังนั้นทำไมเมื่อฉันเปิดใช้งานenv
บน Linux ผลลัพธ์ไม่รวมRANDOM
?
declare -x
เทียบเท่ากับเชลล์ในตัว
คำตอบ:
RANDOM
ไม่ใช่ตัวแปรสภาพแวดล้อม มันเป็นตัวแปรของเชลล์ที่ดูแลโดยเชลล์บางตัว โดยทั่วไปจะไม่ส่งออกโดยค่าเริ่มต้น env
นี่คือเหตุผลที่มันไม่ได้แสดงขึ้นในการส่งออกของ
เมื่อมีการใช้งานอย่างน้อยหนึ่งครั้งมันจะปรากฏขึ้นในผลลัพธ์set
ซึ่งโดยตัวมันเองจะแสดงรายการตัวแปรเชลล์ (และฟังก์ชั่น) และค่าของพวกเขาในเซสชั่นเปลือกปัจจุบัน พฤติกรรมนี้ขึ้นอยู่กับเชลล์และการใช้งานpdksh
บน OpenBSD RANDOM
จะแสดงรายการโดยset
แม้ว่าไม่เคยใช้มาก่อน
ส่วนที่เหลือของคำตอบนี้เกี่ยวข้องกับสิ่งที่คาดว่าจะเกิดขึ้นหากRANDOM
มีการส่งออก (เช่นเปลี่ยนเป็นตัวแปรสภาพแวดล้อม)
การส่งออกด้วยexport RANDOM
จะทำให้ตัวแปรสภาพแวดล้อม แต่การใช้งานจะถูก จำกัด อย่างรุนแรงเนื่องจากค่าในกระบวนการลูกจะเป็น "สุ่ม แต่คงที่" (หมายถึงมันจะเป็นหมายเลขสุ่มไม่เปลี่ยนแปลง) พฤติกรรมที่แน่นอนแตกต่างกันระหว่างเปลือกหอย
ฉันกำลังใช้pdksh
OpenBSD ในตัวอย่างด้านล่างและฉันได้รับค่าสุ่มใหม่ในการawk
ทำงานแต่ละครั้ง(แต่ค่าเดียวกันทุกครั้งภายในawk
อินสแตนซ์เดียวกัน) ใช้bash
ผมจะได้รับสิ่งมูลค่าสุ่มเหมือนกันในทุกawk
สวดของ
$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
25444 25444
$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
30906 30906
ในbash
ค่าที่ส่งออกของRANDOM
จะคงที่โดยไม่คำนึงถึงการใช้งานของRANDOM
เชลล์ (ซึ่งการใช้งานแต่ละครั้ง$RANDOM
จะยังคงให้ค่าใหม่)
นี้เป็นเพราะแต่ละอ้างอิงถึงตัวแปรเปลือก RANDOM
ในbash
ทำให้การเข้าถึงเปลือกภายในของget_random()
ฟังก์ชั่นที่จะให้ตัวแปรสุ่มค่าใหม่ แต่เปลือกไม่ปรับปรุงตัวแปรสภาพแวดล้อม RANDOM
นี่คือที่คล้ายกันในลักษณะการทำงานเช่นเดียวกับแบบไดนามิกอื่น ๆbash
ตัวแปรเช่นLINENO
, SECONDS
, BASHPID
ฯลฯ
การปรับปรุงตัวแปรสภาพแวดล้อมRANDOM
ในการbash
ที่คุณจะต้องมีการกำหนดค่าของตัวแปรเปลือกRANDOM
และการส่งออกมัน
export RANDOM="$RANDOM"
ฉันไม่ทราบแน่ชัดว่าจะมีผลข้างเคียงเพิ่มเติมจากการสร้างตัวสร้างตัวเลขสุ่มอีกครั้งbash
หรือไม่ (แต่การคาดเดาที่ได้รับการศึกษาน่าจะไม่เกิดขึ้น)
RANDOM
ได้มีค่าก่อนที่คุณจะใช้มันได้หรือไม่ ฉันคิดเสมอว่ามันจะมีประชากรเพียงเมื่อเรียก
export RANDOM
หรือแม้กระทั่งdeclare -p RANDOM
มันก็ปรากฏขึ้น แต่ฉันก็ไม่แน่ใจว่ามันมีประโยชน์อะไรที่มันไม่ได้มีอยู่ก่อนที่จะถูกอ้างอิง ...
ไม่ใช่ตัวแปรทั้งหมดที่ตั้งค่าไว้ในเชลล์เซสชั่นของคุณเป็นตัวแปรสภาพแวดล้อม "ตัวแปรสภาพแวดล้อม" หมายถึงเฉพาะตัวแปรที่ส่งออกไปยังสภาพแวดล้อมโดยใช้export
builtin env
คำสั่งเพียงพิมพ์เช่นสภาพแวดล้อมตัวแปร ตัวอย่างเช่น:
$ foo="bar"
$ env | grep foo ## returns nothing
$ export foo
$ env | grep foo ## now, env will print it
foo=bar
หากคุณต้องการดูตัวแปรทั้งหมดที่ตั้งค่าในเซสชันของคุณโดยไม่คำนึงว่าพวกเขาได้ถูกส่งออกหรือไม่คุณสามารถใช้set
:
$ set | grep foo=
foo=bar
set
builtin ยังผลตอบแทนที่ได้ฟังก์ชั่นเพื่อที่จะดูตัวแปรเท่านั้นคุณสามารถใช้:
set | grep '^[^[:space:]]*='
ในที่สุดRANDOM
ตัวแปรนี้มีความพิเศษที่จะกำหนดค่าเฉพาะเมื่อคุณอ้างอิงเท่านั้น สิ่งนี้ถูกกล่าวถึงในbash (1) :
RANDOM
แต่ละครั้งที่มีการอ้างอิงพารามิเตอร์นี้จะมีการสร้างจำนวนเต็มแบบสุ่มระหว่าง 0 ถึง 32767
RANDOM
ลำดับของตัวเลขสุ่มอาจจะเริ่มต้นด้วยการกำหนดค่าให้กับ หากRANDOM
ไม่ได้ตั้งค่าจะสูญเสียคุณสมบัติพิเศษแม้ว่าจะถูกรีเซ็ตในภายหลัง
ดังนั้นแม้ว่ามันจะเป็นตัวแปรสภาพแวดล้อมอย่างที่คุณคิดมันก็จะไม่ปรากฏในenv
เนื่องจากมันจะไม่ถูกตั้งค่าจนกว่าจะเป็นครั้งแรกที่คุณเรียกมันว่า นี่คือสาเหตุที่ไม่ปรากฏใน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
set | grep RAN
นั่นคือการค้นพบที่น่าสนใจเกี่ยวกับ ฉันจะไม่คาดหวังมัน FWIW ฉันเชื่อว่าเอกสารไม่สามารถคาดการณ์ได้
เชลล์ส่วนใหญ่จะมีตัวแปรอื่น ๆ จำนวนหนึ่งที่ตั้งค่าหรือใช้งานโดยเชลล์ที่ไม่ได้ถูกส่งออกไปยังกระบวนการลูกโดยค่าเริ่มต้น
ใน Bash มีบางอย่างที่เจาะจง 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
จากนั้นก็มีคนมาตรฐานมากขึ้นเช่นOPTIND
และOPTERR
(ใช้getopts
) และPS2
, PS3
(แจ้งรอง) และแม้กระทั่งอีก "วิเศษ" ตัวแปร: SECONDS
(แสดงเวลาเป็นวินาทีตั้งแต่เปลือกเริ่มต้น)
declare -p
ในทุบตีคุณสามารถดูตัวแปรทั้งหมดและสถานะของการส่งออกของพวกเขาด้วย คนที่มีเครื่องหมาย-x
ถูกส่งออก, คนที่ไม่มีx
ไม่ได้ (บางส่วนจะมีค่าสถานะอื่นเช่นi
ค่าจำนวนเต็มหรือแบบr
อ่านอย่างเดียว)
ใน Zsh หรือ ksh93 คุณสามารถใช้งานtypeset -p
ได้แม้ว่า Zsh จะทำเครื่องหมายตัวแปรที่ส่งออกโดยเปลี่ยนtypeset
เป็นexport
ในเอาต์พุตแทนที่จะใช้แฟล็ก export
ด้วยตัวเองนอกจากนี้ยังจะแสดงตัวแปรทั้งหมดที่ส่งออก env
แต่ที่เกี่ยวกับผลเดียวกันคุณจะได้รับจากการทำงาน
หากคุณทำเช่นนี้เอกสารจะระบุสิ่งต่อไปนี้:
$RANDOM
เป็นฟังก์ชัน Bash ภายใน(ไม่ใช่ค่าคงที่) ที่ส่งคืนจำนวนเต็มเทียม[1]ในช่วง 0 - 32767 ไม่ควรใช้เพื่อสร้างคีย์การเข้ารหัส
หากคุณใช้strace
คุณจะเห็นว่า$RANDOM
"ตัวแปร" ถูกส่งโดยตรงไปยังคำสั่งราวกับว่ามันเป็นตัวแปรเชลล์สามัญหรือตัวแปรสภาพแวดล้อม แต่มันเป็นเพียงฟังก์ชั่นภายในที่สร้างไว้ในเชลล์ Bash นั่นเป็นการขยายตัว
$ 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
...
เทียบกับตัวแปรปกตินี้:
$ 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
...
ตัวแปรไม่ถูกส่งผ่านเป็นข้อมูลอ้างอิง
$RANDOM
หรือ$SOMEVAR
ผ่านอาร์กิวเมนต์บรรทัดคำสั่งไม่ใช่ตัวแปรสภาพแวดล้อมใช่ไหม คุณต้องการให้export
ทั้งคู่ส่งผ่านสภาพแวดล้อม
strace
การส่งออกไม่ได้ดูเหมือนจะจับการทำงานฟังก์ชั่นภายในโดยเปลือก strace
ในทั้งสองกรณีตัวแปรได้รับการขยายตัวในบรรทัดแรกของ ฉันไม่เข้าใจว่าคุณชี้ไปที่ใด ฉันพลาดอะไรไป
$RANDOM
ขยายตัวจะทำภายในกับเปลือก โดยพื้นฐานแล้วเป็นการยืนยันว่าเชลล์กำหนดค่าและไม่ส่งการอ้างอิงไปยังตัวแปร เปลือกเมื่อมันขยายบรรทัดคำสั่งที่จะดำเนินการแยกวิเคราะห์และส่งแบบฟอร์มการขยายไปยัง$RANDOM
echo
env
ไม่ใช่คำสั่งเชลล์เนื่องจากโดยปกติจะไม่ได้สร้างไว้ในเชลล์