ยกมาเทียบกับการขยายตัวสตริงที่ไม่ได้ยกมา


11
  1. for i in $(xrandr); do echo "$i" ; done
  2. for i in "$(xrandr)"; do echo "$i"; done
  3. for i in "$(xrandr)"; do echo $i; done

ฉันเข้าใจว่าทำไม 1 แตกต่างจาก 2 แต่เหตุใด 3 จึงให้ผลลัพธ์ที่แตกต่างจาก 2 โปรดอธิบายผลลัพธ์ด้วย คำพูดทำงานอย่างไรกับการขึ้นบรรทัดใหม่



คำตอบ:


19

ตัวแปร unquote (ใน$var) หรือการทดแทนคำสั่ง (ใน$(cmd)หรือ`cmd`) เป็นตัวดำเนินการแยก + globในเชลล์คล้ายบอร์น

นั่นคือเนื้อหาจะแบ่งตามค่าปัจจุบันของ$IFSตัวแปรพิเศษ (ซึ่งโดยค่าเริ่มต้นจะมีช่องว่างแท็บและอักขระขึ้นบรรทัดใหม่)

และแต่ละคำที่เป็นผลมาจากการแยกนั้นจะขึ้นอยู่กับการสร้างชื่อไฟล์ (หรือที่รู้จักกันในชื่อการขยายแบบวงกลมหรือชื่อไฟล์ ) นั่นคือพวกเขาถูกพิจารณาว่าเป็นรูปแบบและขยายไปยังรายการไฟล์ที่ตรงกับรูปแบบนั้น

ดังนั้นในfor i in $(xrandr)การ$(xrandr)เพราะมันไม่ได้อยู่ในคำพูดเป็นแยกลำดับของพื้นที่แท็บและตัวอักษรขึ้นบรรทัดใหม่ และแต่ละคำที่เป็นผลมาจากการแยกนั้นจะถูกตรวจสอบเพื่อหาชื่อไฟล์ที่ตรงกัน (หรือปล่อยทิ้งไว้ราวกับว่าพวกเขาไม่ตรงกับไฟล์ใด ๆ ) และforวนซ้ำทั้งหมด

ในfor i in "$(xrandr)"เราไม่ได้ใช้ตัวดำเนินการแยก + glob เนื่องจากมีการอ้างอิงคำสั่งแทนที่ดังนั้นจึงมีหนึ่งรอบในการวนรอบหนึ่งค่า: ผลลัพธ์ของxrandr(โดยไม่มีอักขระขึ้นบรรทัดใหม่ที่ต่อท้ายซึ่งแทนที่แถบคำสั่ง )

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

บทเรียนจึงได้เรียนรู้:

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

โดยปกติในตัวอย่างของคุณด้านบนหากคุณต้องการวนซ้ำรายการคำที่คั่นด้วยช่องว่างในผลลัพธ์ของxrandrคุณจะต้อง:

  • ปล่อยให้$IFSเป็นค่าเริ่มต้น (หรือยกเลิกการตั้งค่า) เพื่อแยกช่องว่าง
  • ใช้set -fเพื่อปิดใช้งานการสร้างชื่อไฟล์เว้นแต่คุณจะแน่ใจว่าxrandrจะไม่ส่งออกใด ๆ*หรือ?หรือ[อักขระ (ซึ่งเป็นอักขระตัวแทนที่ใช้ในรูปแบบการสร้างชื่อไฟล์)

จากนั้นให้ใช้ตัวดำเนินการแยก + glob (ปล่อยให้การแทนที่คำสั่งหรือการขยายตัวตัวแปรแบบไม่มีเครื่องหมายเท่านั้น) ในinส่วนของforลูป:

set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done

หากคุณต้องการวนซ้ำบรรทัด (ไม่ว่าง) ของxrandrเอาต์พุตคุณจะต้องตั้งค่า$IFSเป็นอักขระบรรทัดใหม่:

IFS='
'

4

ขึ้นบรรทัดใหม่ที่ยกมาเป็นขึ้นบรรทัดใหม่ ดังนั้นecho "$1"ให้อาร์กิวเมนต์บรรทัดคำสั่งเดียวเพื่อสะท้อนซึ่งพิมพ์บรรทัดใหม่โดยตรง

ขึ้นบรรทัดใหม่ที่ไม่ได้กล่าวถึงคือช่องว่าง ดังนั้นecho $1ให้อาร์กิวเมนต์บรรทัดคำสั่งจำนวนมากเพื่อสะท้อนซึ่งพิมพ์พวกเขาหนึ่งหลังจากที่อื่นคั่นด้วยช่องว่าง


ขึ้นบรรทัดใหม่ที่ไม่ได้กล่าวถึงคือ whitespaceเป็นทางลัดสั้น ๆ มากเกินไปที่จะเป็นประโยชน์จริง ๆ เป็นคำอธิบายของพฤติกรรมที่นี่ IMO
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.