ตัวแปรเช่น $ 0 และ $ 1 ตัวแปร shell / environment หรือไม่


17

มีตัวแปรในเปลือกเหมือน$0, $1, $2, $?ฯลฯ

ฉันพยายามพิมพ์เชลล์และตัวแปรสภาพแวดล้อมโดยใช้คำสั่งต่อไปนี้:

set

แต่ตัวแปรเหล่านี้ไม่ได้อยู่ในรายการ

ดังนั้นโดยทั่วไปแล้วตัวแปรเหล่านี้ไม่ถือว่าเป็นตัวแปรเชลล์ / สิ่งแวดล้อมใช่ไหม (แม้ว่าจะส่งออกคุณต้องนำหน้าพวกเขาด้วย$เช่นคุณทำกับตัวแปรเชลล์ / สภาพแวดล้อม)


3
พารามิเตอร์ตำแหน่งไม่ใช่ตัวแปร คุณไม่สามารถexport 3เปลี่ยน$3เป็นตัวแปรสภาพแวดล้อมได้ คุณไม่สามารถunset 3; และคุณไม่สามารถกำหนดค่าใหม่โดยใช้$3 3=val
Kaz

คำตอบ:


25

ตัวแปรเป็นหนึ่งในสามพารามิเตอร์ที่แตกต่างกันในเชลล์

  1. ตัวแปรเป็นพารามิเตอร์ที่มีชื่อเป็นตัวระบุเปลือกที่ถูกต้อง; เริ่มต้นด้วยหรือตัวอักษรตามด้วยศูนย์หรือมากกว่าตัวอักษรตัวเลขหรือ__
  2. ตำแหน่งพารามิเตอร์พารามิเตอร์เลข$1, $2...
  3. พิเศษพารามิเตอร์ทั้งหมดมีชื่อตัวเดียวและนอกเหนือจากการ$0ที่พวกเขามีตัวอักษรของทุกวรรคตอนต่างๆ

set แสดงตัวแปรของเชลล์เท่านั้น

เซ็ตย่อยของตัวแปรเชลล์คือตัวแปรสภาวะแวดล้อมซึ่งค่าจะถูกสืบทอดจากสภาพแวดล้อมเมื่อเชลล์เริ่มทำงานหรือถูกสร้างขึ้นโดยการตั้งค่าexportแอ็ตทริบิวต์บนชื่อที่ถูกต้อง


1
โปรดทราบว่าsetจะแสดงพารามิเตอร์ทั้งหมดในzsh(ไม่ใช่ $ 1, $ 2 ... แต่ $ *, $ @) และฟังก์ชั่นใน bash และ bosh เชลล์บางตัวเช่น ksh93 และเวอร์ชันที่เก่ากว่าของเอาต์พุตประ env vars ที่ไม่ได้แม็พกับตัวแปรเชลล์ ( env 1=foo ksh -c setจะพิมพ์1=foo)
Stéphane Chazelas

11

ตัวแปรสภาพแวดล้อมเทียบกับพารามิเตอร์ตำแหน่ง

ก่อนที่เราจะเริ่มพูดคุยเกี่ยวกับ$INTEGERประเภทของตัวแปรเราต้องเข้าใจสิ่งที่พวกเขาเป็นจริงและวิธีที่พวกเขาแตกต่างจากตัวแปรสภาพแวดล้อมตัวแปรเช่นตัวแปรที่$INTEGERเรียกว่าตำแหน่ง สิ่งนี้อธิบายไว้ในมาตรฐาน POSIX (ส่วนต่อประสานระบบปฏิบัติการพกพา) ส่วน 2.1 (เหมืองที่เน้น):

  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ดูที่ตัวแปรสภาพแวดล้อมที่เกิดขึ้นจริงซึ่งคำสั่งทำงาน ดูสิ่งนี้ด้วย


"ในเชลล์เชิงโต้ตอบคุณไม่สามารถอ้างอิง $ 1, $ 2 และอื่น ๆ " มีการอ้างอิงโดยตรงสำหรับสิ่งนี้หรือไม่? ฉันพบกรณีแปลก ๆ ที่ตั้งค่าเหล่านี้ในสภาพแวดล้อมเชลล์แบบโต้ตอบและฉันไม่แน่ใจว่าสิ่งนี้จะถือว่าเป็น 'ที่ไม่ได้มาตรฐาน' หรือไม่
user5359531

@ user5359531 จริงๆแล้วฉันไม่แน่ใจว่าฉันได้รับจากที่ใด อาจเป็นเพราะย้อนกลับไปเมื่อฉันโพสต์คำตอบในปี 2560 ฉันอาจจะอ้างอิงว่าคุณไม่สามารถทำอะไรได้1="foo"แต่หลังจากนั้นฉันพบว่าคำนิยาม POSIX เป็น "คำ" (นั่นคือชื่อของวัตถุเช่นตัวแปรหรือฟังก์ชั่น) ไม่สามารถเริ่ม ด้วยตัวเลข (ดูคำถามที่ฉันโพสต์ในหัวข้อ ) apparently พารามิเตอร์ตำแหน่งเป็นข้อยกเว้นกฎนี้
Sergiy Kolodyazhnyy

@ user5359531 ฉันลบส่วนหนึ่งของคำตอบออกเนื่องจากไม่แม่นยำโดยเฉพาะ คุณสามารถอ้างอิง$1, $2และอื่น ๆ ในเปลือกโต้ตอบและในความเป็นจริงที่ทำกับsetคำสั่งมักจะได้รับรอบ/bin/shข้อ จำกัด ของการไม่ได้มีอาร์เรย์ ขอขอบคุณที่แจ้งเรื่องนี้ให้ฉันทราบ ฉันจะแก้ไขคำตอบในอีกไม่กี่วันข้างหน้าเนื่องจากต้องการการขัดพิเศษและการอัปเดต
Sergiy Kolodyazhnyy

ขอขอบคุณสำหรับการชี้แจง. ปัญหาฉันมีคือมีcondaเมื่อคุณเรียกsource conda/bin/activateมันว่าการตรวจสอบสำหรับ$1, $2ฯลฯ มีการตั้งค่าในการสั่งซื้อเพื่อตรวจสอบว่ามันถูกใช้เป็นสคริปต์ที่มีการขัดแย้งหรือไม่ สิ่งนี้กลายเป็นการทำลายระบบที่ตั้งค่าไว้ในสภาพแวดล้อมแบบโต้ตอบด้วยเหตุผลบางประการ ฉันหวังว่าจะทราบว่าพฤติกรรมที่ไม่ได้มาตรฐานนี้เป็นข้อบกพร่องในระบบสำหรับการตั้งค่าตัวแปรเหล่านี้ในสภาพแวดล้อมแบบอินเทอร์แอคทีฟหรือบนโปรแกรมสำหรับใช้เพื่อตรวจสอบว่ามันถูกเรียกใช้เป็นสคริปต์หรือไม่
user5359531

@ user5359531 ฉันขอแนะนำให้คุณส่งรายงานข้อผิดพลาดถึงผู้condaพัฒนาหรือผู้ใดก็ตามที่เป็นผู้เขียนต้นฉบับของสคริปต์ดังกล่าวเนื่องจากการตรวจสอบ${N}พารามิเตอร์เป็นวิธีที่ไม่ถูกต้อง มีคำถามในหัวข้อเดียวกันที่นี่และที่นี่และวิธีการพกพาที่มากขึ้นหรือน้อยลงคือการตรวจสอบว่า${0}เป็นชื่อสคริปต์ในขณะที่bashจริง ๆ แล้วมีตัวแปรสภาพแวดล้อมสำหรับวัตถุประสงค์นั้น
Sergiy Kolodyazhnyy

4

$1, $2, $3, ..., ${10}, ${11}ตัวแปรจะเรียกว่าพารามิเตอร์ตำแหน่งและได้รับความคุ้มครองในส่วนของคู่มือการทุบตี3.4.1

3.4.1 พารามิเตอร์ตำแหน่ง

พารามิเตอร์ตำแหน่งคือพารามิเตอร์ที่แสดงโดยหนึ่งหลักหรือมากกว่านั้นนอกเหนือจากหลักเดียว 0 พารามิเตอร์ตำแหน่งจะถูกกำหนดจากอาร์กิวเมนต์ของเชลล์เมื่อมีการเรียกใช้และอาจกำหนดใหม่โดยใช้คำสั่ง set builtin พารามิเตอร์ตำแหน่ง N อาจถูกอ้างถึงเป็น $ {N} หรือเป็น $ N เมื่อ N ประกอบด้วยตัวเลขหลักเดียว พารามิเตอร์ตำแหน่งอาจไม่ได้รับมอบหมายให้กับคำสั่งมอบหมาย ชุดตัวสร้างและตัวเลื่อนถูกใช้เพื่อตั้งค่าและยกเลิกการตั้งค่า (ดูที่คำสั่งของ Shell Builtin) พารามิเตอร์ตำแหน่งจะถูกแทนที่ชั่วคราวเมื่อเรียกใช้ฟังก์ชั่นเชลล์ (ดูฟังก์ชั่นเชลล์)

เมื่อพารามิเตอร์ตำแหน่งที่ประกอบด้วยตัวเลขมากกว่าหนึ่งหลักถูกขยายจะต้องอยู่ในเครื่องหมายวงเล็บ

สำหรับ$?และพารามิเตอร์พิเศษ$0เหล่านี้จะกล่าวถึงในส่วนถัดไปมาก3.4.2

3.4.2 พารามิเตอร์พิเศษ

เชลล์ปฏิบัติต่อพารามิเตอร์หลายอย่างเป็นพิเศษ พารามิเตอร์เหล่านี้สามารถอ้างอิงได้เท่านั้น ไม่อนุญาตให้มอบหมายงานให้

...

?

($?) ขยายไปยังสถานะออกของไปป์ไลน์เบื้องหน้าที่ดำเนินการล่าสุด

0

($ 0) ขยายเป็นชื่อของเชลล์หรือสคริปต์เชลล์ นี่คือการตั้งค่าที่เริ่มต้นเปลือก หากมีการเรียกใช้ Bash ด้วยไฟล์คำสั่ง (ดู Shell Scripts) ระบบจะตั้งค่า $ 0 เป็นชื่อของไฟล์นั้น หาก Bash เริ่มต้นด้วยตัวเลือก -c (ดู Invoking Bash) ดังนั้น $ 0 จะถูกตั้งค่าเป็นอาร์กิวเมนต์แรกหลังจากสตริงที่จะดำเนินการหากมีอยู่ มิฉะนั้นจะถูกตั้งค่าเป็นชื่อไฟล์ที่ใช้เรียก Bash ตามที่กำหนดโดยอาร์กิวเมนต์ศูนย์


4

$1, $2... เป็นพารามิเตอร์ตำแหน่งซึ่งไม่ใช่ตัวแปรทำให้เกิดตัวแปรสภาพแวดล้อมเพียงอย่างเดียว

ในบอร์นเหมือนคำศัพท์เปลือก$somethingที่เรียกว่าพารามิเตอร์การขยายตัว (ยังครอบคลุม${something#pattern}และอื่น ๆ ในเปลือกหอยบางอย่างเช่น${array[x]}, ${param:offset}, ${x:|y}และผู้ประกอบการขยายตัวอื่น ๆ อีกมากมาย)

มีพารามิเตอร์หลายประเภท:

  • ตัวแปรที่ชอบ$foo,$PATH
  • พารามิเตอร์ตำแหน่ง ( $1, $2... อาร์กิวเมนต์ที่สคริปต์ของคุณได้รับ)
  • พารามิเตอร์พิเศษอื่น ๆ ชอบ$0, $-, $#, $*, $@, $$, $!, $?...

ชื่อตัวแปรใน Bourne like shells ต้องเริ่มต้นด้วยอักขระตัวอักษรหนึ่งตัว (ใด ๆ ที่รู้จักโดยโลแคลหรือ จำกัด a-zA-Z ขึ้นอยู่กับเชลล์) และขีดล่างและตามด้วยอักขระศูนย์หรืออักขระขีดล่างหรือขีดล่าง

ตัวแปรสามารถมีประเภทที่แตกต่างกัน (สเกลาร์, อาร์เรย์, แฮช) หรือกำหนดคุณลักษณะบางอย่าง (อ่านอย่างเดียวส่งออกตัวพิมพ์เล็ก ... )

บางส่วนของตัวแปรเหล่านั้นถูกสร้างขึ้นโดยเปลือกหรือมีความหมายพิเศษไปยังเปลือก (เช่น$OPTIND, $IFS, $_... )

ตัวแปรเชลล์ที่มีการส่งออกแอตทริบิวต์จะถูกส่งออกโดยอัตโนมัติขณะที่ตัวแปรสภาพแวดล้อมเพื่อให้คำสั่งที่รันเปลือก

ตัวแปรสภาพแวดล้อมเป็นแนวคิดที่แยกจากตัวแปรเชลล์ การเอ็กซ์พอร์ตตัวแปรเชลล์ไม่ใช่วิธีเดียวที่จะส่งผ่านตัวแปรสภาพแวดล้อมไปยังการดำเนินการของคำสั่ง

VAR=foo
export VAR
printenv VAR

จะส่งVARตัวแปรสภาพแวดล้อมไปยังprintenvคำสั่ง (ซึ่งเราบอกให้พิมพ์เนื้อหา) แต่คุณยังสามารถทำได้:

env VAR=foo printenv VAR

หรือ:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'

เช่น

ตัวแปรสภาพแวดล้อมสามารถมีชื่อใด ๆ (สามารถมีอักขระใดก็ได้ แต่=และอาจว่างเปล่า) ไม่ใช่ความคิดที่ดีที่จะตั้งชื่อที่เข้ากันไม่ได้กับชื่อตัวแปรเชลล์แบบบอร์นกับตัวแปรสภาพแวดล้อม แต่เป็นไปได้:

$ env '#+%=whatever' printenv '#+%'
whatever

เชลล์จะแม็พตัวแปรสภาพแวดล้อมที่พวกเขาได้รับกับตัวแปรเชลล์เฉพาะสำหรับตัวแปรสภาพแวดล้อมเหล่านั้นที่มีชื่อเป็นตัวแปรเชลล์ที่ถูกต้อง (และในเชลล์บางตัวจะไม่สนใจสิ่งพิเศษบางอย่างเช่น$IFS)

ดังนั้นในขณะที่คุณสามารถส่งผ่าน1ตัวแปรสภาพแวดล้อมไปยังคำสั่ง:

$ env '1=whatever' printenv 1
whatever

ไม่ได้หมายความว่าการเรียกเชลล์ด้วยตัวแปรสภาพแวดล้อมนั้นจะตั้งค่า$1พารามิเตอร์:

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo

3

ไม่นี่คือพารามิเตอร์ของสคริปต์ ตัวอย่างเช่นถ้าคุณเรียกสคริปต์ของคุณเช่น:

mynicescript.sh one two three

จากนั้นภายในสคริปต์จะมีพารามิเตอร์เหล่านี้เป็น

$1 = one
$2 = two
$3 = three

และ $ 0 คือชื่อของสคริปต์นั้น

ดังนั้นเมื่อคุณอยู่นอกสคริปต์ตัวแปรเหล่านี้จึงไม่สามารถใช้ได้ (ยกเว้น $ 0 ซึ่งแสดง / bin / bash - ตัวเชลล์เอง)


"ดังนั้นเมื่อคุณอยู่นอกสคริปต์ตัวแปรเหล่านี้ไม่พร้อมใช้งาน"คุณหมายถึงอะไร"นอกสคริปต์"เพราะฉันสามารถเห็นค่าของตัวแปรเหล่านี้ในเทอร์มินัลของฉัน
user7681202

2
@ user7681202: อันไหนที่คุณเห็นในเทอร์มินัลของคุณ $0จะชี้ไปที่กระบวนการเทอร์มินัลปัจจุบันของคุณ (อาจทุบตี) และ$?เป็นเพียงรหัสทางออกของกระบวนการสุดท้าย
Jesse_b

ฉันพยายามเรียกใช้gnome-terminalด้วยอาร์กิวเมนต์ ( gnome-terminal Hello World) ฉันจะได้เห็น$0แต่ฉันไม่สามารถมองเห็นและ$1 $2
user7681202

@Jesse_b ขอบคุณฉันได้เพิ่มเนื้อหาของ $ 0 ลงในคำตอบ
Jaroslav Kucera

1
@ user7681202 เทอร์มินัล gnome ไม่ใช่เปลือกมันเป็นโปรแกรมจำลองเทอร์มินัล (เช่น xterm, konsole ฯลฯ ) เชลล์รันภายในเทอร์มินัลและสามารถเป็น bash / sh / zsh / tcsh และอื่น ๆ อีกมากมาย สคริปต์เป็นไฟล์เรียกทำงานที่มีส่วนหัวที่เหมาะสม (เช่น #! / bin / bash) และเนื้อหาที่ตีความได้โดยเชลล์ที่ระบุในรูปแบบ มันมักจะใช้คำต่อท้าย. sh
Jaroslav Kucera
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.