รายการองค์ประกอบที่มีช่องว่างใน zsh


10

ฉันได้ศึกษา zsh scripting เป็นเวลา 2 ชั่วโมงแล้วและฉันก็ตีกำแพง ฉันต้องการดูรายการไฟล์ที่อาจมีช่องว่างอยู่ ฉันเปิดให้วิธีที่แตกต่างอย่างสิ้นเชิงกว่าตัวอย่างต่อไปนี้ตราบใดที่พวกเขากำลัง zsh เนื่องจาก zsh คือสิ่งที่ฉันกำลังศึกษาไม่ใช่งานที่ฉันพยายามเขียน

files=(`ls`)
for f in $files; do
    print $f
done

เห็นได้ชัดว่าฉันไม่เพียงแค่สร้างlsใหม่ฉันแค่ต้องการ$fจับชื่อไฟล์ทั้งหมดในแต่ละการวนซ้ำของลูป

คำตอบ:


12

ครั้งแรกฉันคิดว่าการใช้lsเป็นเพียงตัวอย่าง คุณไม่สามารถแยกวิเคราะห์เอาต์พุตของlsในเชลล์ใด ๆ เนื่องจากไม่ชัดเจน อ่านทำไมคุณไม่ควรวิเคราะห์ผลลัพธ์ของ ls (1)หากนี่เป็นข่าวสำหรับคุณ ในเปลือกใด ๆ ที่จะได้รับรายชื่อของไฟล์, files=(*)การใช้สัญลักษณ์เช่น

ใน zsh เช่นเดียวกับเชลล์อื่น ๆ ผลลัพธ์ของการทดแทนคำสั่งแบ่งออกเป็นคำที่อักขระช่องว่าง (แม่นยำยิ่งขึ้นตามค่าของIFS) (ต่างจากเชลล์อื่น ๆ , ผลลัพธ์ของการทดแทนคำสั่งไม่ขึ้นอยู่กับการกลมใน zsh) ดังนั้นหากเอาต์พุตของlsคำสั่งคือ

hello world
wibble

แล้วfiles=($(ls))กำหนดfilesอาร์เรย์จะมี 3 องค์ประกอบ: hello, และworldwibble

หากการทดแทนคำสั่งอยู่ในเครื่องหมายคำพูดคู่จะไม่มีการแยก คุณสามารถดำเนินการแยกที่กำหนดเองกับธงขยายตัวพารามิเตอร์ ใช้การ@ตั้งค่าสถานะเพื่อระบุว่าผลลัพธ์ของการแยกจะเป็นอาร์เรย์ (ผิดปกติคุณต้องคงการขยายในเครื่องหมายคำพูดคู่เช่น"${(@)…}"แม้ว่าสตริงที่ยกมาสองครั้งจะขยายไปหลายคำ) สำหรับการแบ่งให้ใช้sธงเช่น"${(@s:,:)…}"แยกที่เครื่องหมายจุลภาค การfแบ่งธงที่บรรทัดใหม่เท่านั้น

files=("${(@f)$(ls)}")

โปรดทราบว่าวิธีที่เหมาะสมในการวนซ้ำแถวทั่วไปโดยทั่วไปจะfor f in $files[@]เป็นการ$filesดึงองค์ประกอบที่ว่างเปล่าออก (ที่นี่มันไม่สำคัญเพราะองค์ประกอบจะไม่ว่างเปล่า)

print $fตีความ$fว่าเป็นสวิทช์ถ้ามันเริ่มต้นด้วยและขยายเครื่องหมายใน- $fใช้print -r -- $fหรือprint -rn -- $fถ้าคุณไม่ต้องการเพิ่มบรรทัดใหม่หลังสตริง


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

สิ่งหนึ่งที่ฉันพบว่าทำให้เกิดความสับสนคือเหตุใดการแสดงออกด้านนอก () ในไฟล์ของคุณ = ("$ {(@ f) $ (ls)}") จำเป็นต้องใช้นิพจน์กับ @f หรือไม่ และเพียงแค่เล่น (f) ดูเหมือนว่าจะทำงานได้ดีตราบใดที่ () ปรากฏขึ้นที่ด้านนอก
Koobz

@Koobz 1. ด้านนอก(…)เป็นสิ่งที่จำเป็นเพื่อให้filesเป็นอาร์เรย์และไม่ได้เป็นสตริง (ซึ่งจะมีการต่อกันของบรรทัดจากคำสั่งให้ยกเลิกการแยกทำโดย(f)) 2. foo=$'one\n\nthree', contrast พิมพ์ -rl $ {(ฉ) foo} print "${(@f)foo}"`และ จำเป็นต้องใช้เครื่องหมายคำพูดคู่เพื่อคงบรรทัดว่างไว้ซึ่งคุณจะไม่ได้รับlsแต่สามารถเกิดขึ้นได้กับคำสั่งอื่น
Gilles 'หยุดชั่วร้าย'

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

@Koobz เหตุผลสำหรับการดูแลคำศัพท์พิเศษที่ว่างเปล่าคือความเข้ากันได้ในอดีตกับ zsh เวอร์ชั่นเก่าที่ถูกลืมไปนาน เหตุผลที่ไม่แยกกันโดยอัตโนมัติก็คือมันเป็นพฤติกรรมที่น่าแปลกใจและมักไม่เป็นที่ต้องการ การแยกอัตโนมัติเป็นลักษณะการทำงานของเชลล์เป้าหมายที่ zsh ไม่ได้จำลองถ้าคุณไม่บอก
Gilles 'หยุดความชั่วร้าย'

2

ใน zsh คุณสามารถใช้การขยายตัวของเชลล์ซึ่งไม่ได้ทำการแยกคำตามค่าเริ่มต้น ลอง

for f in /path/to/files/*; do
    print ${f}
done
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.