ตัวแปรแบบฟอร์มนี้คืออะไร = $ (…)


9

หมายความว่าอะไรต่อไปนี้:

basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")

ฉันสนใจเป็นพิเศษในส่วนนี้:

varible=$(...)

ฉันรู้ว่าจะใช้วงเล็บในการดำเนินการ subprocess แต่ถ้าพวกเขาจะใช้ร่วมกับ$?


3
หากคุณกำลังใช้ bash: ดูใน man-page ผ่านman bashและค้นหาการทดแทนคำสั่ง
Flo

คำตอบ:


16

จากคู่มือ Bash ( man bash):

   การทดแทนคำสั่ง
       การทดแทนคำสั่งอนุญาตให้เอาต์พุตของคำสั่งเพื่อแทนที่
       ชื่อคำสั่ง มีสองรูปแบบ:

              $ (คำสั่ง)
       หรือ
              `command`

       Bash ทำการขยายตัวโดยการดำเนินการคำสั่งใน subshell
       สภาพแวดล้อมและแทนที่การทดแทนคำสั่งด้วยมาตรฐาน
       เอาต์พุตของคำสั่งโดยลบบรรทัดใหม่ต่อท้าย ที่ฝัง
       การขึ้นบรรทัดใหม่จะไม่ถูกลบ แต่อาจถูกลบระหว่างคำ
       รุนแรง การแทนที่คำสั่ง $ (ไฟล์ cat) สามารถถูกแทนที่ด้วย
       เทียบเท่า แต่เร็วกว่า $ (ไฟล์ <)

(ซึ่งถือเป็นจริงสำหรับทุกบอร์นเหมือนเปลือกหอยคือsh, ksh, zsh, bashฯลฯ และzshยังสามารถที่จะจับข้อมูลที่มีตัวอักษร NUL ฝังตัวในลักษณะนี้)

คำสั่ง

basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")

จะกำหนดชื่อของไดเรกทอรีที่สคริปต์ตั้งอยู่ (ในขณะที่ยังมีการเปลี่ยนแปลงเครื่องหมายทั้งหมดลงทับ) basedirให้กับตัวแปร ข้อผิดพลาดคำเตือนหรือข้อความวินิจฉัยอื่น ๆ ที่ถูกส่งไปยังสตรีมข้อผิดพลาดมาตรฐานจะยังคงแสดงอยู่บนเครื่อง ( $(...)จับเฉพาะเอาต์พุตมาตรฐานของคำสั่ง)

เชลล์จะเริ่มต้นด้วยการดำเนินการแทนค่าคำสั่ง innermost:

echo "$0" | sed -e 's,\\,/,g'

การส่งออกของที่จะได้รับเป็นสตริงไปและเอาท์พุทของการที่จะได้รับมอบหมายให้กับตัวแปรdirnamebasedir

เครื่องหมายคำพูดคู่อยู่ที่นั่นเพื่อให้แน่ใจว่าไม่มีการแบ่งคำหรือชื่อไฟล์ที่จะทำมิฉะนั้นคุณอาจพบว่าสคริปต์ล้มเหลวหรือสร้างผลลัพธ์แปลก ๆ เมื่อ$0(ชื่อของสคริปต์รวมถึงเส้นทางที่ใช้เรียกใช้) มีช่องว่าง ตัวอักษรหรือชื่อไฟล์ตัวอักษรกลม (เช่น?หรือ*)

โดยทั่วไปแล้วเป็นความคิดที่ดีที่จะอ้างอิงการขยาย (การขยายตัวแปรการแทนที่คำสั่งและการขยายเลขคณิต) ดูคำถามนี้และคำตอบสำหรับคำอธิบายที่ดีว่าทำไมนี่เป็นความคิดที่ดี

หากสคริปต์ถูกเรียกใช้งานเป็น

$ /usr/local/bin/script.sh

แล้วจะได้รับค่าของbasedir/usr/local/bin

หรือบน Cygwin:

$ bash c:\\Users\\Me\\script.sh

แล้วจะได้รับค่าของbasedir c:/Users/Meแบ็กสแลชคู่บนบรรทัดคำสั่งในกรณีนี้คือเพื่อหลีกเลี่ยงแบ็กสแลชเดี่ยวจากเชลล์ มูลค่าที่แท้จริงของการมี$0c:\Users\Me\script.sh

อีกวิธีหนึ่งในการทำสิ่งเดียวกันโดยไม่ต้องใช้dirname, echoและsedจะเป็น

basedir="${0//\\//}"
basedir="${basedir%/*}"

ขอบคุณดังนั้นโดยทั่วไปมันเริ่มแยกจากวงเล็บในสุดใช่มั้ย และทำไมต้องใช้เครื่องหมายคำพูด?
Max Koretskyi

@ Maximus ถูกต้อง ฉันได้อัปเดตคำตอบของฉันพร้อมข้อมูลเพิ่มเติมแล้ว
Kusalananda

บางทีคุณควรพูดว่า "ถือเป็นจริงสำหรับเชลล์ที่เหมือนบอร์นทั้งหมด" ชัดเจนกว่านี้
Sergiy Kolodyazhnyy

@Serg ทราบว่าบอร์นเชลล์ (เช่น/bin/shของ Solaris 10 หรือก่อนหน้า) $(...)ไม่ได้รับการสนับสนุน
Stéphane Chazelas

@ StéphaneChazelasฉันจะรวมสิ่งนี้
Kusalananda

6

มันหมายถึงการเรียกใช้สิ่งที่อยู่ภายในวงเล็บในsubshellและกลับมาว่าเป็นความคุ้มค่าvaribleในกรณีของคุณกำหนดว่า


5

การทดแทนคำสั่งที่varible=$(..)เรียกว่าและมันไม่มีความหมายอะไรนอกจากการเรียกใช้คำสั่งเชลล์และเก็บเอาต์พุตไปยังตัวแปรหรือแสดงกลับโดยใช้คำสั่ง echo ตัวอย่างเช่นแสดงวันที่และเวลา:

echo "Today is $(date)"

และเก็บไว้ในตัวแปร:

SERVERNAME=$(hostname)

สำหรับข้อมูลเพิ่มเติม: https://www.cyberciti.biz/faq/unix-linux-bsd-appleosx-bash-assign-variable-command-output/

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