มีบางกรณีที่จำนวนช่องว่างมีความสำคัญในสคริปต์ทุบตี (หรือเชลล์อื่น ๆ )


14

ฉันได้รับแจ้งว่าช่องว่างมีความสำคัญในbashหรือเชลล์สคริปต์อื่น ๆ และฉันไม่ควรเปลี่ยนการมีอยู่ของช่องว่างเว้นแต่ว่าฉันรู้ว่าฉันกำลังทำอะไรอยู่ โดย "เปลี่ยนการดำรงอยู่" ฉันหมายถึงการแทรกช่องว่างระหว่างอักขระที่ไม่ใช่ช่องว่างสองตัวหรือลบช่องว่างระหว่างอักขระที่ไม่ใช่ช่องว่างสองตัวเช่นการเปลี่ยนvar="$val"เป็นvar ="$val"หรือกลับกัน ฉันต้องการถาม

มีกรณีใดบ้างที่ใช้ช่องว่างเดียวหรือใช้ช่องว่างต่อเนื่องหลายรายการในเชลล์สคริปต์สร้างความแตกต่าง? .

(แน่นอนการแทรก / ลบช่องว่างในเครื่องหมายคำพูดสร้างความแตกต่างเช่นเปลี่ยนจากecho "a b"เป็นecho "a b"หรือกลับกันฉันกำลังมองหาตัวอย่างนอกเหนือจากตัวอย่างเล็กน้อย)

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

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม รวมเปลือกหอยให้มากขึ้นถ้าเป็นไปได้

คำตอบ:


19

นอกเหนือจากเครื่องหมายคำพูดเชลล์ใช้ช่องว่าง (ช่องว่างแท็บขึ้นบรรทัดใหม่ carriage-return ฯลฯ ) เป็นตัวคั่นคำ / โทเค็น นั่นหมายความว่า:

  • สิ่งที่ไม่แยกจากกันโดยช่องว่างจะถือว่าเป็นหนึ่งใน "คำว่า"
  • สิ่งที่คั่นด้วยอักขระช่องว่างอย่างน้อยหนึ่งตัวถือเป็นคำสองคำ (หรือมากกว่า)

จำนวนตัวอักษรช่องว่างที่แท้จริงระหว่าง "สิ่ง" แต่ละรายการไม่สำคัญตราบใดที่มีอย่างน้อยหนึ่งตัว


ขอขอบคุณ. ฉันไม่พบตัวอย่างตัวนับใด ๆ ด้วยตัวเอง ฉันแค่ต้องการให้แน่ใจ
Weijun Zhou

2
Bash ยังถือว่าฟีดฟอร์มและแท็บแนวตั้งเป็นช่องว่าง
fpmurphy

จริง ฉันเขียน '... newlines, etc' แต่เดิมแล้วเปลี่ยนเป็นเพิ่ม carriage-return ปล่อย 'etc' โดยไม่ตั้งใจ
cas

จะทำอย่างไรถ้าจำนวนของช่องว่างมีขนาดใหญ่มากโปรแกรมไม่สามารถใส่หน่วยความจำได้?
Worse_Username

7
@Worse_Username ช่องว่างไม่จำเป็นต้องพอดีกับหน่วยความจำ ฉันเพิ่งสร้างสคริปต์ 48GB บนเครื่องที่มี RAM 8GB และ swap 20GB มันวิ่งได้ดี มันใช้เวลา 3 นาทีในการกระทืบช่องว่างทั้งหมดนั้น แต่ในที่สุดมันก็ประสบความสำเร็จในการรันechoคำสั่งด้วยช่องว่างขนาดใหญ่นั้นระหว่างคำสั่งและการโต้แย้ง
kasperd

23

นี่อาจเป็นการโกง แต่สิ่งนี้:

rm foo\ bar         # "delete the file named 'foo bar'"

แตกต่างจากนี้:

rm foo\  bar        # "delete the files named 'foo ' and 'bar'"

แม้ว่าช่องว่างไม่ได้อยู่ในเครื่องหมายคำพูด ;-)

ยิ่งสับสน

rm \
    foo          # "delete the file named 'foo'"

แตกต่างจากนี้:

rm \ 
    foo          # "delete the file named ' ', then run the command 'foo'"

แม้ว่าพวกเขาจะดูเหมือนกัน!


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

12

ถ้าเราไม่ได้พูดคุยเกี่ยวกับตัวละครพื้นที่ ( U+0020) แต่ใดอักขระช่องว่าง ( U+0020, \n, \tฯลฯ ) แล้วกรณีหนึ่งโดยเฉพาะอย่างยิ่งมาในใจของฉัน: ที่นี่-เอกสาร

รหัสนี้ (ใช้ช่องว่าง):

cat <<- 'EOF'
<space><space>foo
EOF

จะพิมพ์:

  foo

แต่รหัสนี้ (ใช้แท็บ):

cat <<- 'EOF'
<tab><tab>foo
EOF

จะพิมพ์:

foo

นั่นเป็นเพราะ ( เป็นสถานะ POSIX ):

หากโอเปอเรเตอร์การเปลี่ยนเส้นทางคือ<<-ตัวอักขระ <tab> นำหน้าทั้งหมดจะต้องถูกแยกออกจากบรรทัดอินพุตและบรรทัดที่มีตัวคั่นต่อท้าย


1
นั่นน่าสนใจ. ฉันคิดเกี่ยวกับเอกสารที่นี่ แต่ไม่รู้จักตัว<<-ดำเนินการ ขอบคุณมาก.
Weijun Zhou

ที่นี่เอกสารเป็นรูปแบบของข้อความที่ยกมาไม่ใช่รหัสเปลือก การแยกคำของเชลล์ใช้ไม่ได้
cas

2

นอกจากนี้ยังมีผลเมื่อเขียนคำสั่งมอบหมาย เช่นถ้าผมบอกว่าFOO=xyzมันจะสร้างตัวแปรสภาพแวดล้อมที่มีชื่อFOOที่มีค่าxyzแต่ถ้าผมแยกเท่ากับที่มีพื้นที่ก็จะคิดว่าฉันเรียกใช้โปรแกรมชื่อกับหาเรื่องFOO =xyzดังนั้นมันจึงมีความสำคัญเมื่อมันมาถึงไวยากรณ์บางอย่าง


โดยปกติFOO=xyzจะสร้างตัวแปรเชลล์ภายใน แต่ไม่ใช่ตัวแปรสภาพแวดล้อม คุณต้องการset -aหรือexport FOO=xyzสิ่งนั้น (นั่นคือทำให้มันเป็นส่วนหนึ่งของสภาพแวดล้อมของการประมวลผลย่อยที่ไม่ใช่ subshell)
Hauke ​​Laging
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.