มีexport
ไว้เพื่ออะไร
อะไรคือความแตกต่างระหว่าง:
export name=value
และ
name=value
มีexport
ไว้เพื่ออะไร
อะไรคือความแตกต่างระหว่าง:
export name=value
และ
name=value
คำตอบ:
export
ทำให้ตัวแปรพร้อมใช้งานสำหรับกระบวนการย่อย
นั่นคือ,
export name=value
หมายความว่าชื่อตัวแปรพร้อมใช้งานสำหรับกระบวนการใด ๆ ที่คุณเรียกใช้จากกระบวนการเชลล์นั้น หากคุณต้องการให้กระบวนการใช้ประโยชน์จากตัวแปรนี้ให้ใช้export
และเรียกใช้กระบวนการจากเชลล์นั้น
name=value
หมายความว่าขอบเขตตัวแปรถูก จำกัด ไว้ที่เชลล์และไม่สามารถใช้ได้กับกระบวนการอื่น ๆ คุณจะใช้สิ่งนี้สำหรับตัวแปรวงวนตัวแปรชั่วคราวเป็นต้น
สิ่งสำคัญคือต้องทราบว่าการส่งออกตัวแปรไม่สามารถใช้ได้กับกระบวนการหลัก นั่นคือการระบุและส่งออกตัวแปรในกระบวนการที่เกิดขึ้นไม่ได้ทำให้เกิดขึ้นในกระบวนการที่เปิดตัว
name=value command
ไม่command
ทำให้ตัวแปรที่มีอยู่ในกระบวนการย่อย
เพื่อแสดงสิ่งที่คำตอบอื่น ๆ พูด:
$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar
bash-3.2$
al$ foobar="Whatever" bash
คนอื่นตอบว่าการส่งออกทำให้ตัวแปรพร้อมใช้งานสำหรับ subshells และนั่นถูกต้อง แต่เป็นผลข้างเคียงเท่านั้น เมื่อคุณส่งออกตัวแปรจะทำให้ตัวแปรนั้นอยู่ในสภาพแวดล้อมของเชลล์ปัจจุบัน (เช่นเชลล์เรียกputenv(3)
หรือsetenv(3)
)
สภาพแวดล้อมของกระบวนการสืบทอดมาจาก exec ทำให้ตัวแปรมองเห็นได้ใน subshells
แก้ไข (ด้วยมุมมอง 5 ปี): นี่เป็นคำตอบที่โง่ วัตถุประสงค์ของ 'การส่งออก' คือการทำให้ตัวแปร "อยู่ในสภาพแวดล้อมของคำสั่งที่เรียกใช้งานในภายหลัง" ไม่ว่าคำสั่งเหล่านั้นจะเป็น subshells หรือกระบวนการย่อย การติดตั้งแบบไร้เดียงสาจะทำให้ตัวแปรอยู่ในสภาพแวดล้อมของเชลล์ แต่สิ่งนี้จะทำให้ไม่สามารถนำไปใช้งานexport -p
ได้
bash
การส่งออกไม่แน่นอนเพิ่มตัวแปรสภาพแวดล้อมของเปลือกปัจจุบัน dash
แต่นี้ไม่ได้เป็นกรณีที่มี สำหรับฉันแล้วดูเหมือนว่าการเพิ่มตัวแปรให้กับสภาพแวดล้อมของเชลล์ปัจจุบันเป็นวิธีที่ง่ายที่สุดในการใช้ซีแมนทิกส์ของสิ่งที่ง่ายที่สุดexport
แต่พฤติกรรมนั้นไม่ได้รับคำสั่ง
dash
จะทำอย่างไรกับสิ่งนี้ bash
โปสเตอร์เดิมถูกถามเฉพาะเกี่ยวกับ
bash
แต่ใช้กับตัวแปร bourne-shell อย่างเท่าเทียมกัน การเจาะจงมากเกินไปและให้คำตอบที่นำไปใช้เฉพาะกับbash
เป็นความชั่วร้ายที่ยิ่งใหญ่
bash
คือ jQuery ของเชลล์
export makes the variable available to subshells, and that is correct
นี่เป็นการใช้คำศัพท์ที่สับสนอย่างมาก Subshells ไม่จำเป็นต้องexport
สืบทอดตัวแปร กระบวนการย่อยทำ
มันบอกว่ามันไม่จำเป็นที่จะต้องส่งออกในทุบตีเมื่อวางไข่ subshells ในขณะที่คนอื่นพูดตรงข้ามแน่นอน มันเป็นสิ่งสำคัญที่จะต้องทราบความแตกต่างระหว่าง subshells (ผู้ที่ถูกสร้างขึ้นโดย()
, ``
, $()
หรือลูป) และกระบวนการย่อย (กระบวนการที่จะเรียกตามชื่อเช่นตัวอักษรbash
ที่ปรากฏในสคริปต์ของคุณ)
สิ่งที่พบได้ทั่วไปในโครงสร้างทั้งสองนี้คือไม่สามารถส่งผ่านตัวแปรกลับไปยังเชลล์พาเรนต์ได้
$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:
มีอีกหนึ่งแหล่งที่มาของความสับสน: บางคนคิดว่าการแยกย่อย 'forked' เป็นสิ่งที่ไม่เห็นตัวแปรที่ไม่ถูกส่งออก โดยปกติ fork () s จะตามมาทันทีด้วย exec () s และนั่นคือสาเหตุที่ดูเหมือนว่า fork () เป็นสิ่งที่มองหาในขณะที่ในความเป็นจริงมันคือ exec () คุณสามารถเรียกใช้คำสั่งโดยไม่ต้อง fork () ก่อนอื่นด้วยexec
คำสั่งและกระบวนการที่เริ่มต้นด้วยวิธีนี้จะไม่มีการเข้าถึงตัวแปรที่ไม่ได้ส่งออก:
$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export
โปรดทราบว่าเราไม่เห็นparent:
บรรทัดในเวลานี้เนื่องจากเราได้เปลี่ยนพาเรนต์เชลล์ด้วยexec
คำสั่งดังนั้นจึงไม่มีอะไรเหลือให้ดำเนินการคำสั่งนั้น
&
) ยังสร้าง subshell
var=asdf bash -c 'echo $var'
หรือvar=asdf exec bash -c 'echo $var'
? asdf
เอาท์พุทเป็น ;
ทำให้ความแตกต่างถ้าวางอยู่หลังคำนิยามตัวแปร คำอธิบายจะเป็นอย่างไร ดูเหมือนว่าvar
(โดยไม่;
) เกี่ยวข้องกับการเกิด subprocess อย่างใดเนื่องจากเปลือกต้นกำเนิดไม่มีอะไรเกี่ยวข้องกับมัน echo $var
พิมพ์อะไรถ้าดำเนินการในบรรทัดที่สอง แต่สิ่งหนึ่งที่เรียงรายให้var=asdf bash -c 'echo $var'; echo $var
asdf\nasdf
export NAME=value
สำหรับการตั้งค่าและตัวแปรที่มีความหมายต่อกระบวนการย่อย
NAME=value
สำหรับตัวแปรชั่วคราวหรือตัวแปรลูปส่วนตัวในกระบวนการเชลล์ปัจจุบัน
ในรายละเอียดเพิ่มเติมexport
ทำเครื่องหมายชื่อตัวแปรในสภาพแวดล้อมที่คัดลอกไปยังกระบวนการย่อยและกระบวนการย่อยเมื่อสร้าง ไม่มีชื่อหรือค่าที่ถูกคัดลอกกลับมาจากกระบวนการย่อย
ข้อผิดพลาดทั่วไปคือการวางช่องว่างรอบเครื่องหมายเท่ากับ:
$ export FOO = "bar"
bash: export: `=': not a valid identifier
เฉพาะตัวแปรที่ส่งออก ( B
) เท่านั้นที่เห็นโดยกระบวนการย่อย:
$ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
A is . B is Bob
การเปลี่ยนแปลงในกระบวนการย่อยไม่เปลี่ยนเชลล์หลัก:
$ export B="Bob"; echo 'B="Banana"' | bash; echo $B
Bob
ตัวแปรที่ทำเครื่องหมายเพื่อส่งออกมีค่าที่คัดลอกเมื่อสร้างกระบวนการย่อย:
$ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
[1] 3306
$ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash
Subprocess 1 has B=Bob
Subprocess 2 has B=Banana
[1]+ Done echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
เฉพาะตัวแปรที่ส่งออกเท่านั้นที่กลายเป็นส่วนหนึ่งของสภาพแวดล้อม ( man environ
):
$ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
BOB=Bob
ดังนั้นตอนนี้มันควรจะชัดเจนเช่นเดียวกับดวงอาทิตย์ของฤดูร้อน! ขอบคุณ Brain Agnew, alexp และ William Prusell
export
จะทำให้ตัวแปรพร้อมใช้งานสำหรับเชลล์ทั้งหมดที่แยกจากเชลล์ปัจจุบัน
ควรสังเกตว่าคุณสามารถส่งออกตัวแปรและเปลี่ยนค่าในภายหลัง ค่าที่เปลี่ยนแปลงของตัวแปรจะพร้อมใช้งานสำหรับกระบวนการลูก เมื่อส่งออกการตั้งค่าสำหรับตัวแปรคุณต้องทำexport -n <var>
เพื่อลบคุณสมบัติ
$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
ดังที่คุณทราบแล้ว UNIX อนุญาตให้กระบวนการมีชุดของตัวแปรสภาพแวดล้อมซึ่งเป็นคู่ของคีย์ / ค่าทั้งที่เป็นคีย์และค่าเป็นสตริง ระบบปฏิบัติการมีหน้าที่เก็บคู่เหล่านี้ไว้สำหรับแต่ละกระบวนการแยกกัน
โปรแกรมสามารถเข้าถึงตัวแปรสภาพแวดล้อมผ่าน UNIX API นี้:
char *getenv(const char *name);
int setenv(const char *name, const char *value, int override);
int unsetenv(const char *name);
กระบวนการสืบทอดตัวแปรสภาพแวดล้อมจากกระบวนการพาเรนต์ ระบบปฏิบัติการมีหน้าที่สร้างสำเนาของ "envars" ทั้งหมดในขณะที่กระบวนการลูกถูกสร้างขึ้น
Bashในบรรดา shell อื่น ๆ สามารถตั้งค่าตัวแปรสภาพแวดล้อมตามคำขอของผู้ใช้ นี่คือสิ่งที่export
มีอยู่สำหรับ
export
เป็นคำสั่ง Bash เพื่อตั้งค่าตัวแปรสภาพแวดล้อมสำหรับ Bash ตัวแปรทั้งหมดที่ตั้งค่าด้วยคำสั่งนี้จะสืบทอดโดยกระบวนการทั้งหมดที่ Bash นี้สร้างขึ้น
เพิ่มเติมเกี่ยวกับสิ่งแวดล้อมใน Bash
ตัวแปรอีกประเภทใน Bash คือตัวแปรภายใน เนื่องจาก Bash ไม่ได้เป็นเพียงเชลล์แบบโต้ตอบเท่านั้นจริงๆแล้วมันเป็นล่ามสคริปต์เช่นเดียวกับล่ามอื่น ๆ (เช่น Python) จึงสามารถเก็บชุดตัวแปรไว้ได้ ควรกล่าวว่า Bash (ซึ่งแตกต่างจาก Python) รองรับเฉพาะตัวแปรสตริงเท่านั้น
name=value
สัญกรณ์สำหรับการกำหนดตัวแปรทุบตี ตัวแปรเหล่านี้อยู่ใน Bash และไม่มีส่วนเกี่ยวข้องกับตัวแปรสภาพแวดล้อมที่เก็บไว้ในระบบปฏิบัติการ
เพิ่มเติมเกี่ยวกับพารามิเตอร์ของเชลล์ (รวมถึงตัวแปร)
นอกจากนี้ยังควรสังเกตว่าตามคู่มืออ้างอิง Bash:
สภาพแวดล้อมสำหรับคำสั่งง่ายๆใด ๆ หรือฟังก์ชั่นอาจจะเติมชั่วคราวโดย prefixing ด้วยการมอบหมายพารามิเตอร์ที่อธิบายไว้ในเชลล์พารามิเตอร์ คำสั่งการมอบหมายเหล่านี้มีผลกับสภาพแวดล้อมที่เห็นโดยคำสั่ง
เพื่อสรุปสิ่งต่างๆ:
export
ใช้เพื่อตั้งค่าตัวแปรสภาพแวดล้อมในระบบปฏิบัติการ ตัวแปรนี้จะพร้อมใช้งานสำหรับกระบวนการลูกทั้งหมดที่สร้างโดยกระบวนการทุบตีปัจจุบันหลังจากนั้นคำตอบที่ได้รับการยอมรับหมายถึงนี้ แต่ฉันต้องการให้ชัดเจนการเชื่อมต่อกับ builtins เปลือก:
ดังกล่าวแล้วexport
จะทำให้ตัวแปรพร้อมใช้งานทั้งเชลล์และลูก ๆ หากexport
จะไม่ใช้ตัวแปรเดียวที่จะสามารถใช้ได้ในเปลือกและมีเพียงเปลือกbuiltinsสามารถเข้าถึงได้
นั่นคือ,
tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin
นี่เป็นอีกตัวอย่าง:
VARTEST="value of VARTEST"
#export VARTEST="value of VARTEST"
sudo env | grep -i vartest
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'
โดยใช้การส่งออก VARTEST เท่านั้นมูลค่าของ VARTEST นั้นมีอยู่ใน sudo bash -c '... '!
สำหรับตัวอย่างเพิ่มเติมดู:
bash-hackers.org/wiki/doku.php/scripting/processtree
ผู้สร้างสองคนของ UNIX คือ Brian Kernighan และ Rob Pike อธิบายเรื่องนี้ในหนังสือ "The UNIX Programming Environment" Google สำหรับชื่อเรื่องและคุณจะพบเวอร์ชัน pdf ได้อย่างง่ายดาย
พวกเขากล่าวถึงตัวแปรเชลล์ในส่วนที่ 3.6 และมุ่งเน้นไปที่การใช้export
คำสั่งที่ส่วนท้ายของส่วนนั้น:
เมื่อคุณต้องการทำให้ค่าของตัวแปรเข้าถึงได้ใน sub-shells คำสั่ง export ของ shell ควรถูกใช้ (คุณอาจคิดว่าทำไมไม่มีวิธีส่งออกค่าของตัวแปรจากเชลล์ย่อยไปยังพาเรนต์ของมัน)
เพียงเพื่อแสดงความแตกต่างระหว่างตัวแปรที่ส่งออกที่อยู่ในสภาพแวดล้อม (env) และตัวแปรที่ไม่ได้ส่งออกซึ่งไม่ได้อยู่ในสภาพแวดล้อม:
ถ้าฉันทำสิ่งนี้:
$ MYNAME=Fred
$ export OURNAME=Jim
ดังนั้นจะมีเพียง $ OURNAME เท่านั้นที่ปรากฏใน env ตัวแปร $ MYNAME ไม่ได้อยู่ใน env
$ env | grep NAME
OURNAME=Jim
แต่ตัวแปร $ MYNAME มีอยู่ในเชลล์
$ echo $MYNAME
Fred
โดยค่าเริ่มต้นตัวแปรที่สร้างขึ้นภายในสคริปต์จะพร้อมใช้งานสำหรับเชลล์ปัจจุบันเท่านั้น กระบวนการลูก (sub-shells) จะไม่สามารถเข้าถึงค่าที่ถูกตั้งค่าหรือแก้ไข การอนุญาตให้กระบวนการลูกดูค่าใช้ประโยชน์จากคำสั่งส่งออก
แม้ว่าจะไม่ได้กล่าวถึงอย่างชัดเจนในการอภิปราย แต่ก็ไม่จำเป็นต้องใช้การส่งออกเมื่อวางไข่ subshell จากภายใน bash เนื่องจากตัวแปรทั้งหมดจะถูกคัดลอกลงในกระบวนการลูก
export name=value
มันไม่ใช่พกพา ลองname=value; export name
ใช้โซลูชันแบบพกพาทั้งนี้ขึ้นอยู่กับสิ่งที่คุณต้องการ