ฉันสังเกตเห็นว่า{
สามารถใช้ในการขยายรั้ง:
echo {1..8}
หรือในการจัดกลุ่มคำสั่ง:
{ls;echo hi}
ทุบตีรู้ความแตกต่างได้อย่างไร?
{ls;echo hi}
bash
ไม่ได้ตามกฎหมาย คุณต้องเว้นวรรคหลังวงเล็บปีกกาเปิดและเครื่องหมายอัฒภาคก่อนปิดช่องว่าง
ฉันสังเกตเห็นว่า{
สามารถใช้ในการขยายรั้ง:
echo {1..8}
หรือในการจัดกลุ่มคำสั่ง:
{ls;echo hi}
ทุบตีรู้ความแตกต่างได้อย่างไร?
{ls;echo hi}
bash
ไม่ได้ตามกฎหมาย คุณต้องเว้นวรรคหลังวงเล็บปีกกาเปิดและเครื่องหมายอัฒภาคก่อนปิดช่องว่าง
คำตอบ:
เหตุผลที่ทำให้เข้าใจง่ายคือการมีอยู่ของตัวละครตัวหนึ่ง: space.
การขยายของ Brace ไม่ได้ดำเนินการกับช่องว่าง (ยกเลิกการอ้างอิง)
{...}
รายการความต้องการ (ยกเลิกการอ้าง) ช่องว่าง
คำตอบรายละเอียดมากขึ้นคือวิธีการที่เปลือกแยกวิเคราะห์บรรทัดคำสั่ง
ขั้นตอนแรกในการแยกวิเคราะห์ (เข้าใจ) บรรทัดคำสั่งคือการแบ่งออกเป็นส่วนต่างๆ
ส่วนเหล่านี้ (มักเรียกว่าคำหรือโทเค็น) เป็นผลมาจากการแบ่งบรรทัดคำสั่งที่แต่ละอักขระเมตาจากลิงก์ :
- แยกคำสั่งเป็นโทเค็นที่คั่นด้วยชุดเมตาอักขระที่คงที่: SPACE, TAB, NEWLINE,;, (,), <,>, |, และ & ประเภทของโทเค็นรวมถึงคำคำหลักตัวเปลี่ยนเส้นทางของ I / O และอัฒภาค
Meta-ตัวอักษร: และspacetabenter;,<>|&
หลังจากแยกคำอาจเป็นประเภท (ตามที่เข้าใจโดยเปลือก):
LC=ALL ...
LC=ALL echo
LC=ALL echo "hello"
LC=ALL echo "hello" >&2
เฉพาะในกรณีที่ "สตริงรั้ง" (ไม่มีช่องว่างหรือเมตาอักขระ) เป็นคำเดียว (ตามที่อธิบายไว้ข้างต้น) และไม่ได้ยกมามันเป็นผู้สมัครสำหรับ "รั้งขยาย" ทำการตรวจสอบเพิ่มเติมในโครงสร้างภายในภายหลัง
ดังนั้นสิ่งนี้: {ls,-l}
มีคุณสมบัติเป็น "การขยายรั้ง" ที่จะกลายเป็นls -l
ไม่ว่าจะเป็นfirst word
หรือargument
(ใน bash, zsh แตกต่างกัน)
$ {ls,-l} ### executes `ls -l`
$ echo {ls,-l} ### prints `ls -l`
{ls ,-l}
แต่นี้จะไม่: Bash จะแยกspaceและแยกบรรทัดเป็นสองคำ: {ls
และ,-l}
ซึ่งจะทริกเกอร์command not found
(อาร์กิวเมนต์,-l}
หายไป):
$ {ls ,-l}
bash: {ls: command not found
สายของคุณ: {ls;echo hi}
จะไม่กลายเป็น "การขยายตัวรั้ง" เพราะของสองตัวละครเมตาและ;space
มันจะถูกแบ่งออกเป็นสามส่วนนี้: คำสั่งใหม่:{ls
echo
hi}
เข้าใจว่าเป็น;ต้นเหตุของการเริ่มต้นคำสั่งใหม่ คำสั่ง{ls
จะไม่ได้พบและคำสั่งต่อไปจะพิมพ์hi}
:
$ {ls;echo hi}
bash: {ls: command not found
hi}
หากวางไว้หลังคำสั่งอื่นคำสั่งจะเริ่มคำสั่งใหม่หลังจาก;:
$ echo {ls;echo hi}
{ls
hi}
หนึ่งใน "คำสั่งผสม" เป็นรายการ "รั้ง" { list; }
(คำพูดของฉัน): ในขณะที่คุณสามารถดูจะถูกกำหนดให้มีช่องว่างและปิด
ช่องว่างและมีความจำเป็นเพราะทั้งสองและเป็น " คำสงวน" ;
;{
}
และดังนั้นจึงจะได้รับการยอมรับว่าเป็นคำที่ต้องถูกล้อมรอบด้วยอักขระเมตา (เกือบเสมอspace)
ตามที่อธิบายไว้ในจุดที่ 2 ของหน้าเชื่อมโยง
- ตรวจสอบโทเค็นแรกของแต่ละคำสั่งเพื่อดูว่ามันเป็น .... , {, หรือ (จากนั้นคำสั่งนั้นเป็นคำสั่งผสม
ตัวอย่างของคุณ: {ls;echo hi}
ไม่ใช่รายการ
มันต้องการการปิด;และช่องว่างหนึ่งช่อง (อย่างน้อย) หลังจาก{นั้น สุดท้ายจะถูกกำหนดโดยปิด};
{ ls;echo hi; }
นี่คือรายการ และนี่{ ls;echo hi;}
ก็เป็น (ใช้น้อยกว่าปกติ แต่ใช้ได้) (ขอบคุณ @choroba สำหรับความช่วยเหลือ)
$ { ls;echo hi; }
A-list-of-files
hi
แต่เนื่องจากอาร์กิวเมนต์ (เชลล์รู้ถึงความแตกต่าง) กับคำสั่งมันจะทริกเกอร์ข้อผิดพลาด:
$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'
แต่ระวังสิ่งที่คุณเชื่อว่าเชลล์กำลังวิเคราะห์คำ:
$ echo { ls;echo hi;
{ ls
hi
;
ทำงานเป็นเครื่องหมายอัฒภาคได้แล้วเมตาอักขระ }
{ ls;}
บล็อก{
เป็นคำหลักเปลือกดังนั้นจึงต้องแยกออกมาจากคำถัดไปด้วยช่องว่างในขณะที่ในการขยายตัวรั้งควรจะมีไม่มีช่องว่าง (ถ้าคุณต้องการที่จะรั้งขยายพื้นที่ที่คุณจะต้องหลบหนีมันecho {\ ,a}{b,c}
)
คุณสามารถใช้การขยายรั้งในตอนเริ่มต้นของคำสั่ง:
{ls,.} # expands to "ls ."
คุณไม่สามารถใช้มันเพื่อขยายไปยังบล็อกได้เนื่องจากการแยกวิเคราะห์คำสั่งการจัดกลุ่มเกิดขึ้นก่อนการขยาย:
echo {'{ ls','.;}'} # { ls .;}
{'{ ls','.;}'} # bash: { ls: No such file or directory
มันรู้โดยการตรวจสอบไวยากรณ์ของบรรทัดคำสั่ง ด้วยวิธีเดียวกันกับที่รู้ว่าในนิพจน์echo echo
echo แรกควรถูกใช้เป็นคำสั่งและ echo ที่สองเป็นพารามิเตอร์ของ echo แรก
ในทุบตีมันง่ายมากเนื่องจาก{ cmd; }
ควรมีช่องว่างและเครื่องหมายอัฒภาค อย่างไรก็ตามตัวอย่างเช่นใน zsh ไม่จำเป็น แต่ยังโดยการวิเคราะห์บริบทของ{}
เชลล์สามารถบอกได้ว่าควรทำอะไรกับเนื้อหาของเชลล์
พิจารณาสิ่งต่อไปนี้:
alias 1..3=date
{ 1..3; } #in bash
{1..3} #in zsh
ทั้งส่งคืนวันที่ปัจจุบัน แต่
echo {1..3}
ส่งคืน1 2 3
เนื่องจากเชลล์รู้{}
ในอาร์กิวเมนต์สำหรับคำสั่งecho
ดังนั้นควรขยาย
{
ตามด้วยพื้นที่ที่ไม่มีเครื่องหมายอัญประกาศจะไม่เริ่มต้นการขยายรั้งในทุบตี
{
นั้น พื้นที่ที่ไม่ได้ระบุไม่สามารถอยู่ที่ใดก็ได้เพราะเชลล์แบ่งบรรทัดคำสั่งทั้งหมดในช่องว่าง
ประการแรกคอมโพสิตรั้งต้องเป็นคำด้วยตัวเองและคำแรกของบรรทัดคำสั่ง:
echo { these braces are just words }
ประการที่สองเครื่องมือจัดฟันแต่ละอันไม่พิเศษ (ดังที่คุณเห็นด้านบน) การจัดฟันที่ว่างเปล่านั้นไม่พิเศษเช่นกัน:
echo {} # just the token {}: familiar from the find command
สิ่งที่ไม่มีเครื่องหมายจุลภาคก็เป็นเพียงตัวเอง
echo {abc} # just {abc}
นี่คือที่ที่การกระทำเริ่มต้นขึ้น
echo {a,b} # braces disappear, a b results.
ดังนั้นโดยพื้นฐานแล้วสำหรับการขยายรั้งที่จะเตะเข้าเราจำเป็นต้องมีคำเดียว (ไม่แยกออกเป็นช่องบนช่องว่าง) ซึ่งภายในนั้นเกิดขึ้นอย่างน้อยหนึ่งตัวอย่างของ{...}
ด้านในซึ่งมีเครื่องหมายจุลภาคอย่างน้อยหนึ่งรายการ
นี่อาจเป็นคำแรกในบรรทัดคำสั่งโดยวิธี:
{ls,-l} . # just "ls -l ."
{
ถูกตีความว่าเป็นรายการคำสั่งหากมันปรากฏที่จุดเริ่มต้นของคำสั่งและเป็นส่วนขยายรั้งมิฉะนั้น แต่ฉันไม่แน่ใจ