ลอง:
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'f=${1#./}; mv "$1" "./${f//\//_}"' None {} \;
วิธีนี้ปลอดภัยสำหรับชื่อไฟล์ทั้งหมดแม้แต่ชื่อที่มีบรรทัดใหม่ในชื่อ
มันทำงานอย่างไร
-mindepth 2
สิ่งนี้บอกว่าจะไม่ประมวลผลไฟล์ใด ๆ ที่มีอยู่แล้วในไดเรกทอรีปัจจุบัน
-type f -name '*.pdf'
นี่เป็นการ จำกัด การค้นหาไฟล์ปกติที่มีpdf
นามสกุล
-exec bash -c '...' None {} \;
$1
คำสั่งนี้จะทำงานในสายยกจัดหาชื่อไฟล์เป็นอาร์กิวเมนต์แรก
สำหรับวัตถุประสงค์ของเราสตริงNone
เป็นเพียงตัวยึดตำแหน่ง มันถูกกำหนดให้$0
ภายใต้อนุสัญญาทุบตีเป็นชื่อของคำสั่งที่เรากำลังทำงานอยู่
f=${1#./}; mv "$1" "./${f//\//_}"
สิ่งนี้ (a) ลบคำนำหน้า./
จากชื่อไฟล์และ (b) ย้ายไฟล์ไปยังตำแหน่งที่ต้องการด้วยชื่อใหม่
${1#./}
เป็นตัวอย่างของการทุบตีฯกำจัดคำนำหน้า ส่งคืน strign $1
โดย./
ลบออกจากจุดเริ่มต้น ${f//\//_}
เป็นตัวอย่างของการทุบตีฯเปลี่ยนตัวรูปแบบ ก็จะส่งกลับสตริง$f
กับทุกแทนที่ด้วย/
_
เพื่ออ่านข้อมูลเพิ่มเติมเกี่ยวกับคุณลักษณะเหล่านี้ให้ดูในส่วนman bash
สิทธิการขยายตัวพารามิเตอร์
รุ่นที่มีประสิทธิภาพมากขึ้น
เวอร์ชันด้านบนเรียกใช้ bash สำหรับทุกไฟล์ที่พบ หรือเราสามารถเรียกใช้ bash เพียงครั้งเดียวสำหรับไฟล์หลายไฟล์ที่พบ ในการทำเช่นนี้เราได้รวมคำสั่งไว้ในfor
ลูป
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'for f in "$@"; do f=${f#./}; echo mv "$f" "./${f//\//_}"; done' None {} +
ปัญหาอื่น
สมมติว่าไฟล์ทั้งหมดที่เราต้องการอยู่ในระดับที่สองไดเรกทอรีและเราต้องการไฟล์ย้ายที่จะมีคำสั่งของชื่อไดเรกทอรีกลับเพื่อให้แทนของเราจบลงด้วย./path1_pathA_fileI.pdf
./pathA_path1_fileI.pdf
ในกรณีนี้:
for d1 in */; do d1=${d1%/}; for d2 in "$d1"/*/; do d2=${d2%/}; p="${d2#$d1/}_$d1"; for f in "./$d2"/*.pdf; do echo mv "$f" "./${p}_${f#./$d2/}"; done; done; done
หรือสำหรับผู้ที่ต้องการคำสั่งของพวกเขากระจายออกไปหลายบรรทัด:
for d1 in */
do
d1=${d1%/}
for d2 in "$d1"/*/
do
d2=${d2%/}
p="${d2#$d1/}_$d1"
for f in "./$d2"/*.pdf
do
echo mv "$f" "./${p}_${f#./$d2/}"
done
done
done