เหตุใดจึงต้องมีช่องว่างระหว่าง“ [[” และ“ -e xxx” เป็น ksh?


9

ตัวอย่างเช่นคำสั่งต่อไปนี้ใช้ไม่ได้:

if [[-e xyz]]; then echo File exists;fi

ksh ให้ข้อผิดพลาดดังต่อไปนี้

[[-e: command not found

นั่นเป็นเพราะ "[[-" นั้นคลุมเครือหรือไม่


2
[[เป็นคำหลัก - น่าจะเป็นต้นไม้แยกเปลือกของเปลือกหอยที่ต้องการให้คำหลักต้อง
คั่น

อีกวิธีในการดูมันอาจเป็นไปได้ว่าคุณสามารถเขียนฟังก์ชัน [[-, เชลล์จะรู้วิธีแยกวิเคราะห์ "ทำ e flag บน [[" แทนที่จะเป็น "ทำหน้าที่ [[- on e")
pbhj

คำตอบ:


15

คำอธิบายที่ง่ายที่สุดจะเป็นเพราะในคู่มือก็จะปรากฏเป็น[[ expression ]]ดังนั้นจะต้องมีช่องว่างระหว่าง[[และและปิดexpression ]]แต่แน่นอนว่าเราสามารถพยายามมองลึกลงไปอีก เชลล์มีไวยากรณ์ที่ค่อนข้างซับซ้อนและพึ่งพาแนวคิดของ "การแยกคำ" อย่างหนัก โดยเฉพาะอย่างยิ่ง ksh (1)สถานะด้วยตนเอง:

เชลล์เริ่มต้นแยกวิเคราะห์อินพุตโดยแบ่งเป็นคำ คำซึ่งเป็นลำดับของอักขระถูกคั่นด้วยอักขระช่องว่างสีขาว (ช่องว่างแท็บและขึ้นบรรทัดใหม่) หรืออักขระเมตา (<,>, |,;, และ (และ)) นอกเหนือจากการลบคำเว้นวรรคและแท็บจะถูกละเว้นในขณะที่บรรทัดใหม่มักจะกำหนดคำสั่ง

ดังนั้นตามที่ระบุไว้ในคู่มือลำดับของตัวละคร[[-eถือว่าเป็นคำของเชลล์ kshจะค้นหาคำสั่งดังกล่าวในรายการบิวด์อินและโอเปอเรเตอร์พิเศษ (เช่นforหรือwhile) จากนั้นค้นหาคำสั่งภายนอก - และvoilà - ไม่พบดังนั้นจึงมีข้อความแสดงข้อผิดพลาดเกี่ยวกับคำสั่งที่ไม่พบ

ในกรณี[[นี้ไม่ใช่อักขระพิเศษเมตาเช่นกัน หากพวกเขาเป็น-eส่วนหนึ่งใน[[-eจะถือว่าเป็นคำเปลือกไม่ใช่ข้อโต้แย้งกับ[[ตัวเอง อย่างไรก็ตาม[[คำอธิบายเป็นคำสั่งผสมและคู่มือบอกสิ่งต่อไปนี้:

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

ดังนั้นเพื่อที่[[จะได้รับการยอมรับในฐานะคำสั่งผสมมันจะต้องเป็นคำแรกของคำสั่งหรือรายการคำสั่งซึ่งโดยคำจำกัดความก่อนหน้าของคำว่า "คำว่า" หมายความว่ามันจะต้องถูกคั่นด้วยช่องว่างแท็บหรือบรรทัดใหม่จากอื่น ๆ คำ / ข้อโต้แย้ง


คุณได้ถามในความคิดเห็น : "ทำไม parser ไม่สามารถหยุดทันทีที่พบ" [["รูปแบบและถือว่าเป็นจุดเริ่มต้นของคำสั่งตามเงื่อนไข?" คำตอบสั้น ๆ อาจเป็นเพราะ 1) อิทธิพลของ[วากยสัมพันธ์เนื่องจากเดิมเป็นคำสั่งภายนอกและสำหรับการปฏิบัติตามมาตรฐาน POSIX นั้นมีอยู่ว่าเป็นคำสั่งภายนอกแม้กระทั่งทุกวันนี้และ 2) เพราะตัวแยกวิเคราะห์เชลล์ถูกสร้างขึ้นมา ตัวแยกวิเคราะห์เชลล์สามารถจดจำอักขระพิเศษอื่น ๆ ที่ไม่คั่นด้วยช่องว่าง: echo $((2+2))และ(echo foobar)ทำงานได้อย่างสมบูรณ์แบบ บางทีในอนาคตเมื่อkshการพัฒนาดำเนินการต่อหรือมีปรากฏเป็นส้อมหรือโคลน (ชอบmkshหรือpdksh) [[-eคนที่จะใช้ไวยากรณ์พื้นที่น้อยในการ

ดูสิ่งนี้ด้วย:


3
ฉันคิดว่าใบเสนอราคาด้วยตนเองของ ksh นั้นอยู่ในจุดที่เหมาะสม มันคล้ายกับการเขียนโปรแกรมภาษาอื่น ๆ : ใน C, charคำหลัก แต่คุณยังคงไม่สามารถเขียนcharsomeletter = 'A';และคาดว่า parser charที่จะหยุดหลังจากที่ได้เห็น
Peter - Reinstate Monica

ฉันคิดว่าความแตกต่างที่สำคัญระหว่างตัวอย่างของคุณ "char" และสัญลักษณ์ "[[" ในคำถามก็คือโดยทั่วไปแล้วตัวระบุตัวเลขและตัวอักษรต้องการพื้นที่คั่นเพื่อแยกออกจากที่อื่น ในขณะที่สัญลักษณ์พิเศษเป็นโทเค็นไม่จำเป็นต้องใช้ตัวคั่นพื้นที่
AcBap

เผง ฉันไม่แน่ใจว่าการเปรียบเทียบกับ C มีประโยชน์หรือไม่ ใน C ใครสามารถพูดและคอมไพเลอร์ไม่ได้มีการแยกปัญหาที่เป็นi--<=++j i -- <= ++ j
สกอตต์

@Scott ฉันคิดว่าการเปรียบเทียบ C มีประโยชน์ (และเป็นประเภทที่สองที่ตัวระบุ C อนุญาตเฉพาะตัวอักษรและตัวเลข_) ksh มี(ในฐานะที่เป็นผู้ประกอบการและจะแยกวิเคราะห์เป็น(echo hello) ( echo hello )มันมีif, {, [[และอื่น ๆ ที่คำหลักและifx, {xและ[[xแต่ละคนโทเค็น - เช่นวิธีการcharsomeletterเป็นหนึ่งในโทเค็นซี ในทางตรงกันข้ามการ unquoted (xใน ksh สองราชสกุล - เช่นวิธีการi--สองราชสกุลใน C. สิ่งที่มันแนวคิดแม้หมายความว่าจะเป็นผู้ประกอบการที่แตกต่างระหว่างเปลือกหอยบอร์นสไตล์ (เช่น ksh) และ C แต่ Peter A. ไนเดอร์ชี้ให้เห็นความคล้ายคลึงกันของคำศัพท์จริง
Eliah Kagan

2

เป็นสิ่งสำคัญที่ควรทราบก็คือว่า[เป็นคำสั่งและคำหลักเปลือก[[ในทุบตีและ ksh [จะขึ้นอยู่กับ

[[[ถูกนำมาใช้ในทางที่คล้ายกับ บางครั้งคุณยังสามารถแทนที่[ ]ด้วย[[ ]]กับการเปลี่ยนแปลงในพฤติกรรมไม่ ด้วย[เช่นเดียวกับคำสั่งใด ๆ พื้นที่มีผลบังคับใช้ระหว่างคำสั่งและข้อโต้แย้ง [[เช่นเดียวกับ

/usr/bin/[เราใช้จะมีเพียง ตอนนี้เชลล์ส่วนใหญ่[สร้างขึ้นเพื่อประสิทธิภาพ - แต่ไวยากรณ์เหมือนกัน ในเปลือกหอยที่ให้[[มันทำหน้าที่เป็นมากขึ้นหลากหลาย[ทางเลือก

นี่คือคำอธิบายสำหรับ[ในทุบตี:

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

ดังนั้น[จะเทียบเท่ากับtest(นอกเหนือจากการคาดหวัง]ข้อโต้แย้งในตอนท้าย) help testจะให้รายละเอียดเพิ่มเติมกับมัน help [[คุณสามารถเปรียบเทียบนี้

นอกจากนี้ยังมี man page สำหรับคำสั่งภายนอก[( man \[)

ในกรณีของ

if [[-e
  • ทั้ง[มิได้[[มีคำสั่ง คำเต็ม[[-eคือ
  • if [[-eทำให้การทดสอบสำหรับ / เท็จจริง ดังนั้นคำสั่งจะ[[-eมีอยู่?

นั่นเป็นเพราะ "[[-" นั้นคลุมเครือหรือไม่

ใช่. หรือไม่. [[-eมันคืออะไร: ไม่มีสิ่งใดที่เชลล์เข้าใจดังนั้นจึงถือว่ามันเป็นคำสั่งของมันเอง ;-)


"% help [[" บอกว่า "[[" เป็นคำสั่งแบบมีเงื่อนไข ทำไม parser ไม่สามารถหยุดทันทีที่พบ "[[" รูปแบบและถือว่าเป็นจุดเริ่มต้นของคำสั่งแบบมีเงื่อนไข?
AcBap

@Myloti [[-eเป็นชื่อคำสั่งที่อาจใช้งานได้ (ถ้าดูแปลก)
Gordon Davisson

2

พื้นที่เป็นตัวแยกและเป็นสิ่งจำเป็น ตามที่คุณเห็นจากshellcheck:

$ shellcheck gmail-browse-msgs-algorithm.sh

In gmail-browse-msgs-algorithm.sh line 847:
        [[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
          ^-- SC1035: You need a space after the [[ and before the ]].

(รองรับทั้ง ksh และ bash [[และไม่ทำงานหากไม่มีที่ว่าง Shellcheck ให้ผลลัพธ์ที่เหมือนกันกับสคริปต์ ksh และ bash ที่คล้ายกันที่มีบรรทัด buggy นั้น)

ทำไม deliminators มีความจำเป็นที่จะทำอย่างไรกับราชสกุลและคำศัพท์


โปรดทราบ OP ถามเกี่ยวกับkshเชลล์ในคำถาม Bash ยืม[[ตัวดำเนินการจากkshและในคำถามนี้พฤติกรรมของพวกเขาเหมือนกัน แต่ฉันจะระมัดระวังข้อสันนิษฐานเนื่องจากมีความแตกต่างที่สำคัญระหว่างkshและbashพฤติกรรมและ internals นั่นเป็นเพราะ shellcheck ทำงานกับ bash script อาจไม่จำเป็นต้องเป็นเครื่องมือที่เหมาะสมสำหรับสคริปต์ ksh สิ่งที่ต้องจำไว้ในขณะที่ใกล้เปลือกหอยที่แตกต่างกัน
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy ฉันถูกฉวยโอกาสโดยใช้ shellcheck เพื่อเน้น[[กฎในตัว ฉันไม่ได้คาดเดาว่าkshจะเป็นเชลล์ที่shellcheckสามารถหาข้อผิดพลาดได้ฉันหวังว่าคนอื่นจะชื่นชมkshและbashเป็นล่ามที่ต่างกันสองคน ขอบคุณที่พูดถึงมัน สิ่งที่ควรค่ายิ่งกว่า[[คือการทุบตีในขณะที่[เป็นคำสั่งภายนอก
WinEunuuchs2Unix

ที่จริงแล้ว[เป็น bash ในตัวด้วย :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.htmlแต่คุณไม่ได้อยู่ไกล[หรือtestต้องเป็นคำสั่งภายนอก ในสมัยของบอร์นเชลล์[ในความเป็นจริงคำสั่งภายนอกและยังคงมีอยู่ทุกวันนี้/usr/bin/[เนื่องจาก POSIX ต้องการให้มันเป็นคำสั่งภายนอกpubs.opengroup.org/onlinepubs/009695399/utilities/test.html มีน้อยมากที่ POSIX ต้องการ ถูกสร้างขึ้นในpubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Builtin [สำหรับประสิทธิภาพ
Sergiy Kolodyazhnyy

2
Shellcheck รู้ksh; ใช้ hashbang -s kshหรือ Btw, ksh และทุบตีได้[["สร้างขึ้นใน" แต่มันเป็นคำหลักที่แตกต่าง[ซึ่งเป็นbuiltin เปลือก (ksh:; whence -v [ [[bash type [ [[:) Builtins และคำสั่งภายนอกมีความเหมือนกันทางวากยสัมพันธ์ วิธีหนึ่งที่[[แตกต่างจาก[นั้นคือ[[ระงับการขยายตัวบางอย่างในการโต้แย้งของมันซึ่งมันไม่สามารถเป็นแบบบิลท์อินได้มากเท่าที่{ไม่สามารถจัดกลุ่มได้ นี่อาจจะเป็นเหตุผลที่{x(หรือ[[x) เป็นหนึ่งที่รู้สึกแปลกโทเค็น ฉันคิดว่ามันเป็นสิทธิที่จะพูด builtins และคำหลักlexicallyแต่ไม่ไวยากรณ์ที่คล้ายกัน @SergiyKolodyazhnyy
Eliah Kagan

1
@EliahKagan จริงๆแล้วฉันได้โพสต์คำถามใน U&L เพื่อให้ได้คำตอบที่ถูกต้องเกี่ยวกับสิ่งที่ POSIX คิดเกี่ยวกับสถานการณ์นี้ unix.stackexchange.com/questions/526574/… ภาษาของเชลล์มีความซับซ้อนเพียงพอดังนั้นหวังว่าใครบางคนสามารถอธิบายได้ในแง่ทางการที่เป็นทางการมากขึ้น
Sergiy Kolodyazhnyy

1

[[สามารถเป็นคำสั่งภายนอก! นั่นอาจเป็นโปรแกรมและไม่ใช่ไวยากรณ์ที่เชลล์ของคุณสนับสนุนโดยตรง การสนับสนุนไวยากรณ์ที่ไม่ต้องเว้นวรรคจะเป็นไปได้kshแต่จะล้มเหลวในระบบภายนอก[[ดังนั้นด้วยเหตุผลด้านความเข้ากันได้ดีกว่าเพื่อรักษาพื้นที่ที่ต้องการ

BusyBox กำลังจัดเตรียม[[เป็นคำสั่งภายนอกเช่น


0

เนื่องจาก[[-eสามารถมีส่วนร่วมในการขยายเชลล์ (มันสามารถใช้เช่น

echo [[-e]*

เพื่อแสดงรายการไฟล์ทั้งหมดที่เริ่มต้นด้วยตัวอักษรระหว่าง[และeรวม) มันจะเป็นระเบียบถ้า[และ]เป็นตัวอักษรพิเศษที่ไม่ได้เข้าร่วมในการแยกคำที่ควบคุมโดยช่องว่างตามปกติ

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