ตัวแปรสภาพแวดล้อมเทียบกับพารามิเตอร์ตำแหน่ง
ก่อนที่เราจะเริ่มพูดคุยเกี่ยวกับ$INTEGER
ประเภทของตัวแปรเราต้องเข้าใจสิ่งที่พวกเขาเป็นจริงและวิธีที่พวกเขาแตกต่างจากตัวแปรสภาพแวดล้อมตัวแปรเช่นตัวแปรที่$INTEGER
เรียกว่าตำแหน่ง สิ่งนี้อธิบายไว้ในมาตรฐาน POSIX (ส่วนต่อประสานระบบปฏิบัติการพกพา) ส่วน 2.1 (เหมืองที่เน้น):
- เชลล์เรียกใช้งานฟังก์ชั่น (ดูคำสั่งนิยามฟังก์ชัน) ในตัว (ดูยูทิลิตี้ในตัวแบบพิเศษ) ไฟล์เรียกทำงานหรือสคริปต์ให้ชื่อของอาร์กิวเมนต์เป็นพารามิเตอร์ตำแหน่งหมายเลข 1 ถึง n และชื่อของคำสั่ง (หรือในกรณีของฟังก์ชั่นภายในสคริปต์ชื่อของสคริปต์) เป็นพารามิเตอร์ตำแหน่งหมายเลข 0 (ดูการค้นหาคำสั่งและการดำเนินการ)
ในทางตรงกันข้ามตัวแปรเช่น$HOME
และ$PATH
เป็นตัวแปรสภาพแวดล้อม คำจำกัดความของพวกเขาอธิบายไว้ในมาตรา 8 ของมาตรฐาน :
ตัวแปรสภาพแวดล้อมที่กำหนดไว้ในบทนี้มีผลต่อการทำงานของยูทิลิตี้หลายฟังก์ชั่นและการใช้งาน มีตัวแปรสภาพแวดล้อมอื่น ๆ ที่เป็นที่สนใจของยูทิลิตี้เฉพาะเท่านั้น ตัวแปรสภาพแวดล้อมที่ใช้กับยูทิลิตี้เดียวเท่านั้นที่กำหนดไว้เป็นส่วนหนึ่งของคำอธิบายยูทิลิตี้
สังเกตคำอธิบายของพวกเขา command positional_arg_1 positional_arg_2...
พารามิเตอร์ตำแหน่งจะหมายถึงการปรากฏในหน้าของคำสั่งคือ มีไว้เพื่อให้ผู้ใช้บอกคำสั่งว่าต้องทำอะไรเป็นพิเศษ เมื่อคุณทำecho 'Hello' 'World'
มันจะพิมพ์ออกมาHello
และWorld
สตริงเพราะสิ่งเหล่านี้เป็นพารามิเตอร์ตำแหน่งecho
- สิ่งที่คุณต้องการที่echo
จะทำงาน และecho
ถูกสร้างขึ้นเพื่อให้เข้าใจถึงพารามิเตอร์ตำแหน่งว่าเป็นสตริงที่จะพิมพ์ (นอกเสียจากว่าพวกเขาเป็นหนึ่งในตัวเลือกธงเช่น-n
) หากคุณทำสิ่งนี้ด้วยคำสั่งต่าง ๆ มันอาจไม่เข้าใจว่าอะไรHello
และWorld
เป็นเพราะบางทีมันอาจจะคาดหวังจำนวน โปรดสังเกตว่าพารามิเตอร์ตำแหน่งไม่ใช่ "สืบทอด" - กระบวนการลูกไม่ทราบเกี่ยวกับพารามิเตอร์ตำแหน่งของพาเรนต์ยกเว้นว่าส่งผ่านไปยังกระบวนการย่อยอย่างชัดเจน บ่อยครั้งที่คุณเห็นพารามิเตอร์ตำแหน่งถูกส่งผ่านด้วยสคริปต์ตัวตัดคำ - ซึ่งอาจตรวจสอบอินสแตนซ์ที่มีอยู่แล้วของคำสั่งหรือเพิ่มพารามิเตอร์ตำแหน่งเพิ่มเติมลงในคำสั่งจริงที่จะถูกเรียก
ในทางตรงกันข้ามตัวแปรสภาพแวดล้อมหมายถึงการส่งผลกระทบต่อหลายโปรแกรม พวกเขาเป็นตัวแปรสภาพแวดล้อมเพราะพวกเขาตั้งอยู่นอกโปรแกรม (เพิ่มเติมในด้านล่างนี้) ตัวแปรสภาพแวดล้อมบางอย่างเช่นHOME
หรือPATH
มีรูปแบบเฉพาะความหมายเฉพาะและจะมีความหมายเหมือนกันกับแต่ละโปรแกรม HOME
ตัวแปรจะมีความหมายเหมือนกันกับยูทิลิตี้ภายนอกเช่น/usr/bin/find
หรือเชลล์ของคุณ (และต่อจากสคริปต์) - เป็นโฮมไดเร็กตอรี่ของชื่อผู้ใช้ภายใต้กระบวนการที่ทำงาน โปรดสังเกตว่าตัวแปรสภาพแวดล้อมสามารถใช้เพื่อบัญชีพฤติกรรมการใช้คำสั่งเฉพาะตัวอย่างเช่นUID
ตัวแปรสภาพแวดล้อมสามารถนำมาใช้เพื่อตรวจสอบว่าสคริปต์ทำงานด้วยสิทธิ์พิเศษของรูทหรือไม่และแยกเป็นสาขาเพื่อดำเนินการเฉพาะ ตัวแปรสภาพแวดล้อมเป็นสิ่งที่สืบทอดได้ - กระบวนการลูกจะได้รับสำเนาของสภาพแวดล้อมของผู้ปกครอง ดูเพิ่มเติมหากกระบวนการสืบทอดสภาพแวดล้อมของผู้ปกครองทำไมเราถึงต้องส่งออก
ในระยะสั้นความแตกต่างหลักคือตัวแปรสภาพแวดล้อมตั้งอยู่นอกคำสั่งและไม่ได้หมายถึงการเปลี่ยนแปลง (ปกติ) ในขณะที่พารามิเตอร์ตำแหน่งเป็นสิ่งที่ต้องดำเนินการโดยคำสั่งและพวกเขาเปลี่ยน
ไม่ใช่แค่แนวคิดของเชลล์
สิ่งที่ฉันสังเกตเห็นจากความคิดเห็นก็คือคุณกำลังผสมเทอร์มินัลและเชลล์และแนะนำให้คุณอ่านเกี่ยวกับเทอร์มินัลจริงที่ครั้งหนึ่งเคยเป็นอุปกรณ์ทางกายภาพ ทุกวันนี้ "เทอร์มินัล" ที่เรามักจะอ้างถึงหน้าต่างที่มีพื้นหลังสีดำและข้อความสีเขียวเป็นซอฟต์แวร์จริง ๆ แล้วเป็นกระบวนการ เทอร์มินัลเป็นโปรแกรมที่รันเชลล์ในขณะที่เชลล์เป็นโปรแกรม แต่เป็นโปรแกรมที่อ่านสิ่งที่คุณพิมพ์เพื่อดำเนินการ (นั่นคือถ้าเป็นเชลล์แบบโต้ตอบเชลล์ที่ไม่ใช่แบบโต้ตอบคือสคริปต์และsh -c 'echo foo'
ประเภทของการเรียกใช้) เพิ่มเติมเกี่ยวกับเปลือกหอยที่นี่
นี่คือความแตกต่างที่สำคัญ แต่ก็สำคัญที่ต้องตระหนักว่าเทอร์มินัลนั้นเป็นโปรแกรมและดังนั้นจึงปฏิบัติตามกฎของสภาพแวดล้อมและพารามิเตอร์ตำแหน่งเดียวกัน ของคุณgnome-terminal
เมื่อเริ่มจะมองไปที่คุณSHELL
ตัวแปรสภาพแวดล้อมและวางไข่เปลือกเริ่มต้นที่เหมาะสมสำหรับคุณเว้นแต่คุณจะระบุบางคำสั่งอื่น ๆ -e
ที่มี สมมติว่าผมเปลี่ยนเปลือกเริ่มต้นของฉันไปksh
- คำพังเพยขั้วแล้วจะวางไข่แทนksh
bash
นี่เป็นตัวอย่างของการใช้โปรแกรมโดยสภาพแวดล้อม ถ้าผมบอกอย่างชัดเจนgnome-terminal
ด้วย-e
การใช้เปลือกเฉพาะ - มันจะทำมัน แต่มันจะไม่เป็นแบบถาวร ในทางตรงกันข้ามสิ่งแวดล้อมหมายถึงไม่เปลี่ยนแปลงส่วนใหญ่ (เพิ่มเติมในภายหลัง)
ดังนั้นอย่างที่คุณเห็นสภาพแวดล้อมและตัวแปรตำแหน่งทั้งคุณสมบัติของกระบวนการ / คำสั่งไม่ใช่แค่เปลือก เมื่อพูดถึงเชลล์สคริปพวกเขายังติดตามโมเดลที่ตั้งค่าด้วยภาษาโปรแกรม C ยกตัวอย่างmain
ฟังก์ชั่นC ซึ่งโดยทั่วไปจะดูเหมือน
int main(int argc, char **argv)
ที่ใด argc
คือจำนวนอาร์กิวเมนต์บรรทัดคำสั่งและargv
อาร์เรย์ของพารามิเตอร์บรรทัดคำสั่งอย่างมีประสิทธิภาพจากนั้นก็มีenviron
ฟังก์ชั่น (บน Linux นั่นman -e 7 environ
) เพื่อเข้าถึงสิ่งต่าง ๆ เช่นเส้นทางไดเรกทอรีหลักของผู้ใช้รายการไดเรกทอรีPATH
ที่เราสามารถมองหาไฟล์ปฏิบัติการได้ ฯลฯ เชลล์สคริปต์ถูกสร้างแบบจำลองในลักษณะที่คล้ายกัน ในคำศัพท์เปลือกเรามีพารามิเตอร์ตำแหน่ง$1
, $2
และอื่น ๆ ในขณะที่$#
คือจำนวนของพารามิเตอร์ตำแหน่ง เกี่ยวกับ$0
อะไร นั่นคือชื่อของตัวปฏิบัติการเองซึ่งเป็นรูปแบบอีกครั้งจากภาษาการเขียนโปรแกรม C - argv[0]
จะเป็นชื่อของ "ปฏิบัติการ" ของคุณ และนี่คือธรรมที่เป็นจริงสำหรับการเขียนโปรแกรมและการเขียนสคริปต์ภาษามากที่สุด
กระสุนแบบโต้ตอบกับไม่มีการโต้ตอบ
หนึ่งในสิ่งที่ผมเคยพูดเป็นนัย ๆ แล้วความแตกต่างระหว่างเปลือกหอยโต้ตอบและไม่โต้ตอบ พรอมต์ที่คุณพิมพ์คำสั่ง - มันเป็นแบบโต้ตอบมันโต้ตอบกับผู้ใช้ ในทางตรงกันข้ามเมื่อคุณมีเชลล์สคริปต์หรือคุณเรียกใช้bash -c''
นั่นไม่ใช่แบบโต้ตอบ
และนี่คือสิ่งที่ความแตกต่างสำคัญ เชลล์ที่คุณรันอยู่แล้วเป็นกระบวนการที่ถูกวางไข่ด้วยพารามิเตอร์ตำแหน่ง (สำหรับbash
ล็อกอินเชลล์คือหนึ่ง "... ซึ่งอักขระตัวแรกของอาร์กิวเมนต์ศูนย์คือ - - หรือเริ่มด้วยตัวเลือก --login" ( อ้างอิง ) )
ในทางตรงกันข้ามสคริปต์และเชลล์ที่เปิดตัวพร้อม-c
ตัวเลือกสามารถใช้ประโยชน์จาก$1
และ$2
อาร์กิวเมนต์ ตัวอย่างเช่น
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
โปรดสังเกตว่าฉันเคยใช้ที่sh
นั่นด้วยเพราะ-c
ตัวเลือกเล็ก ๆ น้อย ๆคือการใช้พารามิเตอร์ตำแหน่งแรกและกำหนดให้$0
ซึ่งต่างจากชื่อของโปรแกรม
อีกสิ่งที่สำคัญที่ควรสังเกตคือพารามิเตอร์ตำแหน่งคือสิ่งที่ฉันเรียกว่า "framable" แจ้งให้ทราบว่าเราเปิดตัวครั้งแรกbash
กับพารามิเตอร์ตำแหน่งของตัวเอง แต่พารามิเตอร์ตำแหน่งเหล่านั้นกลายเป็นพารามิเตอร์และecho
stat
และแต่ละโปรแกรมเข้าใจในวิธีของตนเอง ถ้าเราให้กับstat
สตริงHello World
และไม่มีไฟล์Hello World
มันจะสร้างข้อผิดพลาด; bash
ถือว่าเป็นเพียงสตริงธรรมดา แต่stat
คาดว่าสตริงนั้นจะเป็นชื่อไฟล์ที่มีอยู่ ในทางตรงกันข้ามโปรแกรมทั้งหมดจะยอมรับว่าตัวแปรสภาพแวดล้อมHOME
เป็นไดเรกทอรี (เว้นแต่โปรแกรมเมอร์จะเขียนโค้ดด้วยวิธีที่ไม่สมเหตุสมผล)
เราสามารถยุ่งกับตัวแปรสภาพแวดล้อมและพารามิเตอร์ตำแหน่งได้หรือไม่?
โดยทางเทคนิคแล้วเราสามารถยุ่งกับทั้งคู่ แต่เราไม่ควรยุ่งกับตัวแปรสภาพแวดล้อมในขณะที่เรามักจะต้องให้พารามิเตอร์ตำแหน่ง เราสามารถเรียกใช้คำสั่งในเชลล์ด้วยการเพิ่มตัวแปรเช่น
$ hello=world bash -c 'echo $hello'
world
นอกจากนี้เรายังสามารถวางตัวแปรลงในสภาพแวดล้อมเพียงแค่ใช้export variable=value
จากภายในเชลล์หรือสคริปต์ env -c command arg1 arg2
หรือเราสามารถเรียกใช้คำสั่งกับสภาพแวดล้อมที่ว่างเปล่าอย่างสมบูรณ์ด้วย อย่างไรก็ตามโดยทั่วไปจะไม่แนะนำให้ไปยุ่งกับสภาพแวดล้อมโดยเฉพาะอย่างยิ่งการใช้ตัวแปรตัวพิมพ์ใหญ่หรือเขียนทับตัวแปรสภาพแวดล้อมที่มีอยู่แล้ว ขอแนะนำให้สังเกตแม้ว่าจะไม่ใช่แบบมาตรฐาน
สำหรับพารามิเตอร์ตำแหน่งวิธีการตั้งค่านั้นชัดเจนเพียงใส่คำสั่งไว้ล่วงหน้าแต่ยังมีวิธีตั้งค่าอื่น ๆ ที่ชาญฉลาดเช่นเดียวกับการเปลี่ยนรายการพารามิเตอร์เหล่านั้นผ่านshift
คำสั่ง
โดยสรุปแล้ววัตถุประสงค์ของทั้งสองนี้แตกต่างกันและมีอยู่ด้วยเหตุผล ฉันหวังว่าผู้คนจะได้รับข้อมูลเชิงลึกจากคำตอบนี้และมันก็สนุกที่ได้อ่านมันเหมือนกับที่ฉันเขียนคำตอบนี้
หมายเหตุเกี่ยวกับคำสั่ง set
set
คำสั่งตามพฤติกรรมคู่มือชอบ (จากคู่มือการทุบตีเน้นเพิ่ม):
หากไม่มีตัวเลือกชื่อและค่าของตัวแปรเชลล์แต่ละตัวจะแสดงในรูปแบบที่สามารถนำกลับมาใช้ใหม่เป็นอินพุตสำหรับการตั้งค่าหรือรีเซ็ตตัวแปรที่ตั้งค่าไว้ในปัจจุบัน
ในคำอื่น ๆที่มีลักษณะที่ตัวแปรเฉพาะเปลือกบางอย่างที่จะเกิดขึ้นในสภาพแวดล้อมเช่นset
HOME
โดยคำสั่งตัดกันเช่นenv
และprintenv
ดูที่ตัวแปรสภาพแวดล้อมที่เกิดขึ้นจริงซึ่งคำสั่งทำงาน ดูสิ่งนี้ด้วย
export 3
เปลี่ยน$3
เป็นตัวแปรสภาพแวดล้อมได้ คุณไม่สามารถunset 3
; และคุณไม่สามารถกำหนดค่าใหม่โดยใช้$3
3=val