Bash brace expansion หลังพา ธ สแลช


12

ฉันกำลังพยายามคัดลอกไฟล์ไปยังชื่ออื่นในไดเรกทอรีเดียวกันโดยใช้การขยายรั้ง ฉันใช้ bash 4.4.18

นี่คือสิ่งที่ฉันทำ:

cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}

แต่ฉันได้รับข้อผิดพลาดนี้:

cp: cannot stat '/home/xyz/some/dir/{my-file-to-rename.bin,': No such file or directory

แม้แต่การขยายรั้งอย่างง่ายเช่นนี้ก็ทำให้ฉันมีข้อผิดพลาดเดียวกัน

cp {my-file-to-rename.bin, new-name-of-file.bin}

ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


29

ขยายตัวรั้งไวยากรณ์ยอมรับจุลภาค แต่ก็ไม่ยอมรับช่องว่างหลังเครื่องหมายจุลภาคที่ ในหลายภาษาการเขียนโปรแกรมช่องว่างหลังจากเครื่องหมายจุลภาคเป็นเรื่องธรรมดา แต่ไม่ใช่ที่นี่ ใน Bash การมีอยู่ของพื้นที่ที่ไม่ได้ระบุไว้จะช่วยป้องกันไม่ให้เกิดการขยายตัวของรั้ง

ลบพื้นที่และมันจะทำงาน:

cp ~/some/dir/{my-file-to-rename.bin,new-name-of-file.bin}

ในขณะที่ไม่จำเป็นเลยโปรดทราบว่าคุณสามารถย้ายส่วนท้าย.binออกจากวงเล็บปีกกา:

cp ~/some/dir/{my-file-to-rename,new-name-of-file}.bin

หากคุณต้องการทดสอบผลกระทบของการขยายรั้งคุณสามารถใช้echoหรือprintf '%s 'หรือprintfกับสตริงรูปแบบที่คุณต้องการเพื่อทำ (โดยส่วนตัวแล้วฉันใช้echoสำหรับสิ่งนี้เมื่อฉันอยู่ใน Bash เนื่องจากตัวที่สร้างขึ้นของ Bashechoไม่ขยายลำดับการหลบหนีตามค่าเริ่มต้นและเหมาะสมอย่างยิ่งในการตรวจสอบว่าคำสั่งใดจะทำงานจริง) ตัวอย่างเช่น:

ek@Io:~$ echo cp ~/some/dir/{my-file-to-rename,new-name-of-file}.bin
cp /home/ek/some/dir/my-file-to-rename.bin /home/ek/some/dir/new-name-of-file.bin

23

string{foo, bar}ไม่ขยายตัวรั้ง; มันเป็นคำสองคำและstring{foo, bar}ในการใช้การขยายรั้งเครื่องมือจัดฟันจะต้องอยู่ในคำเดียวกัน คุณจะต้องลบพื้นที่พิเศษถ้าคุณไม่ต้องการหรืออ้างมันถ้าคุณต้องการ:

$ printf "%s\n" aa{bb, cc}
aa{bb,
cc}
$ printf "%s\n" aa{bb,cc}
aabb
aacc
$ printf "%s\n" aa{bb," cc"}
aabb
aa cc

+1 สำหรับตัวอย่างที่ชัดเจนและขอบคุณ ฉันจะให้คะแนนโหวตของฉันเมื่อชื่อเสียงของฉันเพียงพอ :)
nanangarsyad

มีอย่างอื่นที่ควรพูดถึงเกี่ยวกับ "คำเปลือก" . . like เชลล์รู้ได้อย่างไรว่าจะแยกคำใด);
Sergiy Kolodyazhnyy

-1

Bash ปฏิบัติต่อพื้นที่นั้นเหมือนอย่างอื่น ในฐานะ IFS ตัวคั่นฟิลด์ภายใน ใช้สำหรับแยกคำหลังจากขยายและแยกบรรทัดเป็นคำด้วยคำสั่ง read builtin

เชลล์ปฏิบัติต่ออักขระแต่ละตัวของ IFS เป็นตัวคั่นและแยกผลลัพธ์ของการขยายอื่น ๆ ออกเป็นคำในตัวอักษรเหล่านี้ หาก IFS ไม่ได้ตั้งค่าหรือค่าของมันคือค่าเริ่มต้นจากนั้นลำดับของและที่จุดเริ่มต้นและจุดสิ้นสุดของผลลัพธ์ของการขยายก่อนหน้านี้จะถูกละเว้นและลำดับของอักขระ IFS ใด ๆ ที่ไม่ได้อยู่ที่จุดเริ่มต้นหรือจุดสิ้นสุด คำ. หาก IFS มีค่าอื่นที่ไม่ใช่ค่าเริ่มต้นลำดับของพื้นที่อักขระและช่องว่างของ whitespace จะถูกละเว้นที่จุดเริ่มต้นและจุดสิ้นสุดของคำตราบใดที่อักขระ whitespace อยู่ในค่าของ IFS (ตัวอักษรช่องว่าง IFS) อักขระใด ๆ ใน IFS ที่ไม่ใช่ช่องว่าง IFS พร้อมกับอักขระช่องว่าง IFS ที่อยู่ติดกันใด ๆ จะคั่นเขตข้อมูล ลำดับของอักขระช่องว่างของ IFS ยังถือว่าเป็นตัวคั่น หากค่าของ IFS เป็นโมฆะ
ทุบตี (1)

โดยการแทรกตัวคั่นที่ไม่ใช้ค่า Escape จากนั้นคุณบอกว่าทุบตีคำสั่งและอาร์กิวเมนต์ของคุณคือ:

  1. "ซีพี"
  2. "~ / บาง / dir / {ฉันไฟล์ไป rename.bin"
  3. "ใหม่ชื่อของ file.bin}"

หากคุณมีคำพูดหรือหลีกเลี่ยง "\" คุณจะต้อง:

  1. "ซีพี"
  2. "~ / some / dir / {my-file-to-rename.bin, \ new-name-of-file.bin}"

ซึ่งจะไม่เป็นสิ่งที่คุณต้องการยกเว้น "new-name-of-file.bin" เป็นชื่อไฟล์ใหม่ที่คุณต้องการ รวมพื้นที่ เมื่อการขยายรั้งเกิดขึ้นก่อนจากนั้นการขยายเครื่องหมายตัวหนอนจะถูกดำเนินการ:

  1. "ซีพี"
  2. "/path/to/home/some/dir/my-file-to-rename.bin"
  3. "/ path / to / home / some / dir / \ new-name-of-file.bin"

เพียงแค่ลบพื้นที่ที่จะแก้ไขทั้งหมดที่


5
นี่เป็นสิ่งที่ดี แต่คุณดูเหมือนจะพูดว่าการแยกคำเกิดขึ้นcp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}และIFSส่งผลต่อผลลัพธ์ ไม่เป็นเช่นนั้น ที่นี่ space เป็นตัวบ่งชี้ในการโทเค็น ( ขั้นตอนที่ 2 ) ดู3.5.7เปิดเมื่อเกิดการแยก ลองแล้วIFS=x printf '[%s]\n' {a,b} printf '[%s]\n' {a, b} printf '[%s]\n' {a,xb} printf '[%s]\n' {a, xb}
Eliah Kagan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.