เหตุใดบางครั้งช่องว่างจึงจำเป็นต้องใช้กับอักขระเมตา


543

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

bash: syntax error near unexpected token `{:'

เมื่อวานมันเกิดขึ้นเมื่อฉันพยายามเรียกใช้ในBash shell ของเพื่อนแล้วฉันก็เพิ่มช่องว่างและมันก็ใช้งานได้ทันที:(){ :|:& };:แทนที่จะเป็น:(){:|:&};:

ช่องว่างสำคัญหรือไม่ มีรอยสักข้อผิดพลาดทางไวยากรณ์ที่แขนของฉัน?!

ดูเหมือนว่าจะทำงานในzshเสมอแต่ไม่ใช่ใน Bash

คำถามที่เกี่ยวข้องไม่ได้อธิบายอะไรเกี่ยวกับช่องว่างซึ่งเป็นคำถามของฉันจริงๆ เหตุใดช่องว่างจึงจำเป็นสำหรับ Bash เพื่อให้สามารถแยกวิเคราะห์ได้อย่างถูกต้อง


6
ฉันโพสต์คำถามเดียวกันที่นี่ (ไม่รวมส่วนรอยสัก)
เบอนัวต์

3
นอกจากนี้เครื่องหมายโคลอน (:) ไม่สามารถใช้เป็นชื่อฟังก์ชันได้ (ดู: pubs.opengroup.org/onlinepubs/9699919799/utilities/ ...... ) ... FreeBSD's / bin / sh ให้ข้อผิดพลาดกับสิ่งนี้ ...
Martin Tournoij

5
@Carpetsmoker: ฉันไม่แน่ใจว่ามันเกี่ยวข้องอย่างไร คำถามนี้เกี่ยวกับ Bash
เดนนิส

คำตอบ:


267

มีรายการของอักขระที่แยกโทเค็นใน BASH ตัวละครเหล่านี้เรียกว่าmetacharactersและพวกเขาจะ|, &, ;, (, ), <, >, พื้นที่และแท็บ ในทางตรงกันข้ามวงเล็บปีกกา ( {และ}) เป็นเพียงตัวอักษรธรรมดาที่ประกอบขึ้นเป็นคำ

เว้นช่องว่างที่สองก่อนที่}จะทำเนื่องจาก&เป็นตัวเปรียบเทียบ ดังนั้นรอยสักของคุณควรมีอักขระเว้นวรรคอย่างน้อยหนึ่งตัว

:(){ :|:&};:

35
วิธีแก้ปัญหาง่าย ๆ : ย้ายส่วนแรกของ taoo ไปทางซ้ายและผิวหนังถ่ายเทระหว่างสองส่วน

23
ฉันชอบคำนี้on the other hand... ปุนตั้งใจ? ;): D (ขออภัยสำหรับความคิดเห็นนอกหัวข้อ)
anishsane

4
แต่นี่จะแตกต่างกันสำหรับ zsh? zsh ต่างกันอย่างไร?
tfogo

2
คำอธิบายที่ดียกเว้นว่า{และ}เป็นคำหลักของเชลล์ในบริบทนี้ เฉพาะในกรณีที่พวกเขาไม่ได้รับการยอมรับเช่นนี้เนื่องจากไม่มีช่องว่าง / อักขระโดยรอบ - พวกเขาจะถือว่าเป็นส่วนที่แท้จริงของคำที่พวกเขากลายเป็นส่วนหนึ่งของ (แล้วมีการขยายรั้งซึ่งเกิดขึ้นในบริบทที่แตกต่างกัน)
mklement0

2
@DmitriChubarov วงเล็บปีกกาได้รับอนุญาตในชื่อคำสั่ง (รวมถึงฟังก์ชั่น: {foo} () { echo hello; }. "ชื่อ" ตามที่กำหนดโดยในbashฐานะ "คำที่ประกอบด้วยตัวอักษรและตัวเลขและขีดล่างและเริ่มต้นด้วยตัวอักษรหรือขีดล่าง" ใช้เฉพาะกับชื่อตัวแปร
chepner

82

เพียงแค่รอยสัก

#!/bin/zsh

shebang ด้านบนมันและคุณจะสบายดี


6
ถ้าเราจู้จี้จุกจิก shebang จะไม่ทำงานเลยในฐานะเชลล์หวังว่า zsh จะอยู่ในโหมดโต้ตอบตามที่ได้รับแจ้งจาก ...
SzG

50

การจัดฟันเป็นเหมือนคำสำคัญแปลก ๆ มากกว่าสัญลักษณ์พิเศษและต้องการช่องว่าง สิ่งนี้แตกต่างจากวงเล็บตัวอย่างเช่น เปรียบเทียบ:

(ls)

ซึ่งใช้งานได้และ:

{ls}

{ls}ซึ่งมีลักษณะสำหรับคำสั่งที่มีชื่อว่า ในการทำงานจะต้องมี:

{ ls; }

lsอัฒภาคหยุดรั้งปิดถูกนำมาเป็นพารามิเตอร์ไป

สิ่งที่คุณต้องทำคือบอกผู้คนว่าคุณกำลังใช้ฟอนต์แบบสัดส่วนกับตัวอักษรที่ค่อนข้างแคบ


12
@DmitriChubarov - มันเป็นเล่ห์เหลี่ยมมากใช้ความหมายที่แตกต่างกันโดยสิ้นเชิงของเครื่องมือจัดฟัน lsจะขยายรายการคั่นด้วยเครื่องหมายจุลภาคของค่าซึ่งในกรณีนี้เป็นเพียง
Peter Westlake

7
แต่…เด็กชาย…คุณจะมีรอยสักตลอดชีวิตของคุณ! คุณทำเครื่องหมายว่าตัวเองเป็นคนโง่อยู่ตลอดเวลา! และจากนั้นคุณอาจไม่ได้รับมันขวาก่อนที่จะมีมันเย็บ? นั่นเป็นสองขั้นตอนที่เกินกว่าจะเป็นคนโง่ฉันเดาว่า ;-) ไม่มีความผิดเพื่อนฉันแค่สงสัย
Alfe

14
@ เกือบฉันจะลองก่อนที่จะสัก แต่ฉันลองมันใน zsh ของฉันฉันคิดว่ามันมีการแยกวิเคราะห์เหมือนกับทุบตี หลอกฉัน แต่ฉันจะบอกคนอื่นว่าเป็น zsh :)
spydon

20
@spydon หรือคุณบอกพวกเขาว่าคุณซ้ายออกจากพื้นที่ในวัตถุประสงค์เพื่อให้ประชาชนคัดลอกคำสั่งจากรอยสักของคุณจะไม่ได้ตั้งใจเรียกใช้และความผิดพลาดเครื่องของพวกเขา;)
โผล่

4
เฮ้ถ้ามันใช้ได้ใน zsh ทำไมไม่ลองเพิ่ม #! / bin / zsh ด้านบน (หรือก่อนหน้า)? เป็นการดีที่จะระบุเชลล์ก่อน
Adam Miller

41

แม้ว่าจะไม่สามารถมองเห็นได้ง่ายในแบบอักษร tatoo มีเครื่องหมาย Byte-Order (BOM) ระหว่างวงเล็บปีกกาและลำไส้ใหญ่ (คุณอาจเมามากพอเมื่อคุณได้รับ tatoo ที่คุณไม่ได้สังเกต แต่มันอยู่ที่นั่นจริงๆ) . สิ่งนี้ทำให้ความเป็นไปได้ที่ชัดเจนสามประการ:

  1. คุณพิมพ์ BOM ล้มเหลวเมื่อคุณถอดรหัส ผลลัพธ์คือแอปพลิเคชั่นที่ชัดเจนของ GIGO เชลล์ไม่รู้จัก BOM ที่ไม่มีอยู่ในการถอดความที่ล้มเหลวของคุณ
  2. เปลือกของคุณเก่าเกินไป ไม่รู้จักอักขระ Unicode ดังนั้น BOM (และอาจเป็นอักขระ Unicode อื่นทั้งหมด) จะถูกละเว้นอย่างสมบูรณ์แม้ว่า BOM ที่ใดก็ได้ แต่จุดเริ่มต้นของไฟล์ควรถือว่าเป็นพื้นที่ที่มีความกว้างไม่เป็นศูนย์ .
  3. เปลือกของคุณใหม่เกินไป การใช้ BOM เป็น ZWNBS เลิกใช้แล้วและผู้เขียนได้ใช้ Unicode รุ่นอนาคตซึ่งการใช้งานนี้ไม่ได้รับอนุญาตอีกต่อไป

40

แล้วฉันก็เพิ่มช่องว่างและทันใดนั้นมันก็ใช้งานได้ ...

เป็นเพราะวิธีการแยกวิเคราะห์เชลล์ {คุณต้องการพื้นที่หลังจากนิยามฟังก์ชันเริ่มต้นคือหลังจากที่

foo() { echo hey& }
foo() { echo hey&}
foo(){ echo hey&}

ถูกต้อง ในทางกลับกัน,

foo() {echo hey&}

ไม่ใช่


คุณต้องมี tatoo แบบนี้:

ป้อนคำอธิบายรูปภาพที่นี่


จากแหล่งที่มา :

  /* We ignore an open brace surrounded by whitespace, and also
     an open brace followed immediately by a close brace preceded
     by whitespace.  */

การเว้นช่องว่างหลังจาก{สาเหตุทำให้{echoถูกตีความเป็นโทเค็นเดียว


รูปแบบที่เทียบเท่า

:(){ :|:& };:

อยากจะเป็น

:(){
:|:& };:

โปรดทราบว่าไม่มีช่องว่างหลังจาก{ในเวอร์ชันสำรอง แต่การแบ่งบรรทัดทำให้เชลล์จดจำ{โทเค็น


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