อธิบายคำสั่งเชลล์: shift $ (($ optind - 1))


30

ฉันไม่ได้เป็นผู้ชาย Linux แต่ติดอยู่ในสคริปต์บางอย่างที่ฉันต้องอ่านสำหรับโครงการของฉัน ดังนั้นทุกคนสามารถช่วยฉันในสิ่งที่คำสั่งนี้กำลังทำอะไรอยู่?

shift $(($optind - 1))

3
ดังที่ระบุไว้ด้านล่าง OPTIND จะต้องเป็นตัวใหญ่และ '$' ในวงเล็บเป็นตัวเลือก
DarkHeart

คำตอบ:


49

shift $((OPTIND-1))(หมายเหตุOPTINDเป็นตัวพิมพ์ใหญ่) โดยปกติจะพบได้ทันทีหลังจากgetopts whileวนรอบ$OPTINDgetoptsเป็นจำนวนตัวเลือกที่พบโดย

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

จากคู่มืออ้างอิง GNU Bash :

getopts ชื่อ optstring [args]

getoptsถูกใช้โดยเชลล์สคริปต์เพื่อวิเคราะห์พารามิเตอร์ตำแหน่ง optstringมีอักขระตัวเลือกที่จะรับรู้; หากตัวละครตามด้วยโคลอนตัวเลือกที่คาดว่าจะมีการโต้แย้งซึ่งควรจะแยกออกจากมันด้วยช่องว่าง ห้ามใช้เครื่องหมายโคลอน (':') และเครื่องหมายคำถาม ('?') เป็นอักขระตัวเลือก ทุกครั้งที่มีการเรียกใช้ให้วางตัวgetoptsเลือกถัดไปในชื่อตัวแปรเชลล์เริ่มต้นnameหากไม่มีอยู่และดัชนีของอาร์กิวเมนต์ถัดไปจะถูกประมวลผลในตัวแปร โดยอัตโนมัติ จะต้องรีเซ็ตด้วยตนเองระหว่างการเรียกหลายครั้งไปยัง ภายในการเรียกใช้เชลล์เดียวกันหากจะใช้ชุดพารามิเตอร์ใหม่OPTINDถ้ามันไม่ได้อยู่และดัชนีของการโต้แย้งต่อไปที่จะนำมาแปรรูปเป็นตัวแปร OPTINDถูกเตรียมใช้งานเป็น 1 ทุกครั้งที่เชลล์หรือเชลล์สคริปต์ถูกเรียกใช้ เมื่อตัวเลือกต้องมีการโต้แย้ง, สถานที่ getopts OPTARGว่าอาร์กิวเมนต์ลงในตัวแปร เชลล์ไม่ได้รีเซ็ตOPTINDgetopts

เมื่อพบตัวเลือกสุดท้ายให้getoptsออกโดยมีค่าส่งคืนมากกว่าศูนย์ OPTINDถูกตั้งค่าเป็นดัชนีของอาร์กิวเมนต์ที่ไม่ใช่ตัวเลือกแรกและชื่อถูกตั้งค่าเป็น '?'

getoptsปกติจะแยกวิเคราะห์พารามิเตอร์ตำแหน่ง แต่ถ้าข้อโต้แย้งมากขึ้นจะได้รับในargs, getoptsแยกวิเคราะห์เหล่านั้นแทน

shift n
ลบnสตริงจากตำแหน่งรายการพารามิเตอร์ ดังนั้นshift $((OPTIND-1))จะลบตัวเลือกทั้งหมดที่ได้รับการแยกวิเคราะห์getoptsจากรายการพารามิเตอร์และหลังจากนั้นจุด$1จะอ้างอิงถึงอาร์กิวเมนต์ที่ไม่ใช่ตัวเลือกแรกที่ส่งผ่านไปยังสคริปต์

ปรับปรุง

ในฐานะที่เป็น mikeserv กล่าวถึงในความคิดเห็นที่shift $((OPTIND-1))อาจไม่ปลอดภัย เพื่อป้องกันการแยกคำอื่น ๆ ที่ไม่พึงประสงค์การขยายพารามิเตอร์ทั้งหมดควรถูกอ้างอิงสองครั้ง ดังนั้นรูปแบบที่ปลอดภัยสำหรับคำสั่งคือ

shift "$((OPTIND-1))"


ดูเหมือนว่าสิ่งนี้จะทำงานได้ก็ต่อเมื่อตัวเลือกทั้งหมดเกิดขึ้นก่อนที่จะมีข้อโต้แย้งเกี่ยวกับตำแหน่งที่เหลืออยู่ แก้ไข?
Steve Jorgensen

@SteveJorgensen: ใช่ถูกต้อง OTOH การวางตัวเลือกหลังจากอาร์กิวเมนต์ที่ไม่ใช่ตัวเลือกขัดแย้งกับ sh / bash Convention โดยทั่วไปแล้วอาร์กิวเมนต์แรกที่ไม่ได้ขึ้นต้นด้วยเครื่องหมายขีดจะแสดงถึงจุดสิ้นสุดของตัวเลือกและ args ที่ตามมาใด ๆ ที่เริ่มต้นด้วยเส้นประจะไม่ถือว่าเป็นตัวเลือก ไม่ใช่ทุกโปรแกรมที่เป็นไปตามอนุสัญญานี้ แต่มันทำให้ชีวิตง่ายขึ้นมากถ้าคุณทำ :)
PM 2Ring

@SteveJorgensen: (ต่อ) หัวข้อนี้จะกล่าวถึงสั้น ๆ ในทำไมยูทิลิตี้บางตัวแยกวิเคราะห์ตัวถูกดำเนินการก่อนตัวเลือก? . ในฐานะที่เป็นความคิดเห็นของ Gilles ต่อคำตอบของ Celada กล่าวถึงบางโปรแกรม (เช่นfind) อาจดูเหมือนว่าพวกเขาอนุญาตตัวเลือกหลังจากที่ไม่ใช่ตัวเลือก แต่พวกเขาไม่: พวกเขามีตัวถูกดำเนินการที่ขึ้นต้นด้วยเส้นประ
PM 2Ring

ขอบคุณสำหรับข้อมูลนั้น (& การแก้ไข) @mosvy นั่นเป็นเรื่องที่ค่อนข้างแปลกIFSแต่ก็ดีกว่าที่จะปลอดภัยกว่าขออภัย ;)
PM

@roaima ถ้าIFS=0123456789, shift $((OPTIND-1))(โดยไม่ต้องใส่เครื่องหมายอัญประกาศ) จะกลายเป็นshift ""สิ่งที่จะถูกเพิกเฉย (ในksh) หรือสร้างข้อผิดพลาด (ในbashและdash)
mosvy

8

$((...))เพียงแค่คำนวณสิ่งของ ในกรณีของคุณใช้ค่าของ$optintและ substracts 1

shiftลบพารามิเตอร์ตำแหน่ง ในกรณีของคุณจะลบoptint-1พารามิเตอร์

สำหรับข้อมูลเพิ่มเติมดูได้ที่help getopts, help shift, ดูที่man bashสำหรับ "การขยายตัวทางคณิตศาสตร์" getoptsและโดยเฉพาะอย่างยิ่งสำหรับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.