การใช้การขยายพารามิเตอร์เพื่อสร้างรายการอาร์กิวเมนต์สำหรับ `mkdir -p`


10

ฉันมีสิ่งนี้:

% ls -1dF /tmp/foo/*
/tmp/foo/000f9e956feab3ee4625aebb65ae7bae9533cdbc/
/tmp/foo/002e34c2218f2c86fefd2876f0e5c2559c5fb3c4/
/tmp/foo/00b483576791bab751e6cb7ee0a7143af43a8069/
.
.
.
/tmp/foo/fedd0f7b545e7ae9600142656756456bc16874d3/
/tmp/foo/ff51ac87609012137cfcb02f36624f81cdc10788/
/tmp/foo/ff8b983a7411395344cad64182cb17e7cdefa55e/

ฉันต้องการที่จะสร้างไดเรกทอรีภายใต้แต่ละไดเรกทอรีย่อยที่อยู่ภายใต้barfoo

ถ้าฉันลองทำสิ่งนี้ด้วย

% mkdir -p /tmp/foo/*/bar

... ฉันได้รับข้อผิดพลาด

zsh: no matches found: /tmp/foo/*/bar

(ในการเข้าใจย้อนหลังฉันสามารถเข้าใจเหตุผลสำหรับข้อผิดพลาด)

ฉันรู้ว่าฉันสามารถแก้ปัญหาเดิมด้วย for-loop ได้ แต่ฉันอยากรู้ว่าzshสนับสนุนการขยายพารามิเตอร์บางรูปแบบที่จะสร้างอาร์กิวเมนต์ที่ต้องการสำหรับการเรียกใช้ครั้งเดียวmkdir -pหรือไม่ IOW การขยายพารามิเตอร์เทียบเท่ากับ "ผนวก/barกับทุกส่วนนำหน้าที่สร้างโดยการขยาย/tmp/foo/*" ทำให้

% mkdir -p /tmp/foo/000f9e956feab3ee4625aebb65ae7bae9533cdbc/bar ... /tmp/foo/ff8b983a7411395344cad64182cb17e7cdefa55e/bar

คำตอบ:


13
setopt histsubstpattern extendedglob
mkdir -p /tmp/foo/*(#q/:s_%_/bar_)

นี้จะขยาย globbingที่มีquiet ธง globที่ใช้คัดเลือก globเพื่อให้ตรงกับเพียงไดเรกทอรีและปรับปรุงการดำเนินการsubstitution (โดยใช้%ตัวอักษรรูปแบบที่จะใช้ได้เฉพาะในรูปแบบประวัติเปลี่ยนตัวโหมด) ที่ผนวกสตริงเพื่อแต่ละคำ

man zshexpn

ว้าวฉันประทับใจมาก ฉันยังพบมันทั้งหมดใน man page ที่คุณระบุ
Wildcard

1
โปรดทราบว่ามีการระบุโปสเตอร์ดั้งเดิมmkdir -pซึ่งจะมีผลแตกต่างกันเล็กน้อยจากคำสั่งของคุณที่จะไม่โยนข้อผิดพลาดหากบางไดเรกทอรีเหล่านั้นมีbarไดเรกทอรีย่อยอยู่แล้ว จุดเล็ก ๆ น้อย ๆ แต่น่าสังเกตที่นี่ :)
สัญลักษณ์แทน

1
อีกวิธีหนึ่งคือการใช้การขยายอาร์เรย์ผ่าน${^spec}และผนวกbarเข้ากับแต่ละองค์ประกอบของสิ่งที่/tmp/foo/*(/)ขยายไป: set -- /tmp/foo/*(/)จากนั้นmkdir -p -- "${^@}/bar"
don_crissti

5

แน่นอน - ใช้วง

for n in /tmp/foo/*; do mkdir "$n/bar";done

globs ใช้เพื่อขยายรายการของรายการที่มีอยู่ไม่ใช่สิ่งที่ยังไม่ได้สร้าง


ขออภัยฉันเกรงว่าคำถามของฉันไม่ได้ระบุไว้อย่างชัดเจน ฉันจะชี้แจงมัน
kjo

2
นี่ไม่ใช่คำตอบหากzshสามารถขยาย globs และต่อท้ายข้อความด้วยไวยากรณ์เดียว แต่ฉันคิดว่าเป็นวิธีเดียวที่จะทำสิ่งที่คุณต้องการ @kjo
Wildcard

4

หากไดเรกทอรีอยู่ในอาร์เรย์คุณสามารถใช้${^...}รูปแบบของการขยาย

a=(/tmp/foo/*/)
mkdir -p ${^a}bar

0

คุณสามารถใช้findและxargsเพื่อ:

find /tmp/foo -maxdepth 1 -mindepth 1 -type d | xargs -i echo mkdir -p {}/bar

ซึ่งใช้-maxdepth 1และ-mindepth 1เพื่อป้องกันการสร้างbarในไดเรกทอรีย่อยของเป้าหมายและใน/tmp/fooตัวเองตามลำดับ type dพิจารณาเฉพาะไดเรกทอรีเท่านั้น

คุณต้องลบechoเพื่อดำเนินการจริงมิฉะนั้นechoจะพิมพ์เฉพาะบรรทัดที่จะดำเนินการเท่านั้น นอกจากนี้คุณยังสามารถใส่ไว้ในการทดแทนต้องการที่$()จะดำเนินการ

Manual says xargs -iเลิกใช้แล้ว แต่ฉันไม่พบทางเลือกที่มีประโยชน์อื่น ๆ เท่า ๆ กันดังนั้นจึงควรใช้งานได้เป็นเวลาหลายปี ... คุณสามารถแทนที่-iด้วย-I'{}'ให้ทันสมัยอยู่เสมอ


คำตอบนี้และอันถัดไปดูดีสำหรับฉัน ใครสามารถอธิบายได้ว่าทำไมพวกเขาถึงควรลงคะแนนเสียง? ลงคะแนนได้ดี แต่เราจะเรียนรู้ได้อย่างไรหากไม่มีเหตุผลให้?
โจ

มันเป็นทางเลือกที่ใช้งานได้ไม่ทำอะไรเลยนอกจากสิ่งที่ OP ถาม เอาชนะฉัน
loa_in_

ฉันคิดว่ามันมีอคติบางอย่างที่คำตอบต้องมีคำตอบที่ไม่ดีดังนั้นความอยุติธรรมจึงทำให้ชื่อเสียงของฉันแย่ลง
loa_in_

ฉันไม่ชอบโหวตที่ไม่ได้อธิบาย แต่ฉันไม่เห็นอคติเช่นนี้ โดยปกติแล้วคำตอบ "ไม่ดี" (คำที่ฉันเข้าใจ) มักจะไม่ดี
Joe

0

@loa_in_ มีประโยชน์ส่วนใหญ่ แต่findเอาต์พุตท่อมีแนวโน้มที่จะเป็นเทรนด์แบบ faux

find /tmp/foo -maxdepth 1 -mindepth 1 -type d -exec mkdir {}/bar \;

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