ลดขนาดไดเรกทอรีทั้งหมดภายใต้ไดเรกทอรี


12

ฉันต้องการพิมพ์เล็กทุกชื่อไดเรกทอรีภายใต้ไดเรกทอรี ฉันสามารถใช้คำสั่งใดได้บ้าง?

คำตอบ:


10

ไดเรกทอรีทั้งหมดในระดับเดียวหรือทำซ้ำ?

zsh

ในระดับหนึ่ง:

autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'

ซ้ำ:

zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'

คำอธิบาย: zmvเปลี่ยนชื่อไฟล์ที่ตรงกับรูปแบบตามข้อความการแทนที่ที่กำหนด -o-iผ่าน-iตัวเลือกให้กับแต่ละmvคำสั่งภายใต้ประทุน (ดูด้านล่าง) ในข้อความทดแทน$1, $2ฯลฯ เป็นกลุ่มวงเล็บต่อเนื่องในรูปแบบ **หมายถึงไดเรกทอรีทั้งหมด (ย่อย) * ซ้ำ ๆ สุดท้าย(/)ไม่ใช่กลุ่มที่ถูกวงเล็บ แต่เป็นตัวระบุแบบกลมหมายถึงการจับคู่ไดเรกทอรีเท่านั้น ${2:l}แปลง$2เป็นตัวพิมพ์เล็ก

แบบพกพา

ในระดับหนึ่ง:

for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done

สุดท้าย/จำกัด การจับคู่ไปยังไดเรกทอรีและmv -iทำให้ขอการยืนยันในกรณีที่มีการปะทะกัน เอาไปเขียนทับในกรณีที่มีการปะทะกันและการใช้งาน-i yes n | for …เพื่อไม่ได้รับพร้อมต์และไม่ทำการเปลี่ยนชื่อใด ๆ ที่จะเกิดการชนกัน

ซ้ำ:

find root/* -depth -type d -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

การใช้-depthเพื่อให้แน่ใจว่ามีการประมวลผลไดเรกทอรีที่ซ้อนกันอย่างลึกซึ้งก่อนบรรพบุรุษของพวกเขา การประมวลผลชื่อขึ้นอยู่กับการเป็น/; หากคุณต้องการเรียกใช้งานในไดเรกทอรีปัจจุบันให้ใช้./*(ปรับเชลล์สคริปต์เพื่อจัดการกับ.หรือ*ถูกทิ้งไว้เป็นแบบฝึกหัดสำหรับผู้อ่าน)

Perl เปลี่ยนชื่อ

ที่นี่ฉันใช้สคริปต์เปลี่ยนชื่อ Perl ที่ Debian และ Ubuntu จัดส่งเป็น/usr/bin/prename(โดยทั่วไปมีให้renameเช่นกัน) ในระดับหนึ่ง:

rename 's!/([^/]*/?)$!\L/$1!' root/*/

วนซ้ำด้วย bash ≥4หรือ zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/

วนซ้ำแบบพกพา:

find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +

อย่างน้อยใน OS X สิ่งนี้จะล้มเหลวหากไดเรกทอรีใด ๆ เป็นตัวพิมพ์เล็ก: mv -i a aให้ "mv: เปลี่ยนชื่อ a / a: อาร์กิวเมนต์ไม่ถูกต้อง"
Janus

@ Janus: ใช่คุณได้รับข้อความแสดงข้อผิดพลาดซึ่งน่าเกลียด (แม้ว่าจะไม่เป็นอันตรายที่บรรทัดคำสั่ง) แต่อย่างไรก็ตามฉันควรใช้ zmv ซึ่งดูแลกรณีนี้
Gilles 'หยุดความชั่วร้าย'

ฉันพบ-execdirสิ่งที่น่ากลัว: unix.stackexchange.com/questions/5412/…ฉันพบว่ามันมีPATHความบ้าคลั่งและเศร้า :-(
Ciro Santilli 冠状病毒审查审查事件法轮功

4

ไม่มีคำสั่งเดียวที่จะทำเช่นนั้น แต่คุณสามารถทำสิ่งนี้:

for fd in */; do
  #get lower case version
  fd_lower=$(printf %s "$fd" | tr A-Z a-z)
  #if it wasn't already lowercase, move it.
  [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done

หากคุณต้องการให้มีประสิทธิภาพคุณควรคำนึงถึงเมื่อมีสองไดเรกทอรีที่แตกต่างกันเฉพาะในกรณี

ในฐานะที่เป็นหนึ่งซับ:

for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done

นี้แสดงให้เห็นถึงตรงกลางผ่านการเขียนของฉัน (พื้นเดียวกัน) ข้อเสนอแนะ:for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
frabjous

ฉันพยายามที่จะทำมันด้วยfind -type dแต่ไม่สามารถทำได้
Michael Mrozek

1
สัญชาตญาณของฉันจะต้องทำfor fd in */;ดังนั้นหลีกเลี่ยงความจำเป็นในการตรวจสอบว่ามันเป็นไดเรกทอรี แต่ฉันไม่รู้ว่าสัญชาตญาณนี้เป็นสิ่งที่ดีหรือไม่
สตีเวนดี

ใช่สำหรับ ... * / จะดีกว่า
Shawn J. Goff

1
@Shawn: trแล้วคาดว่าช่วงเพื่อให้tr '[A-Z]' '[a-z]'แปล[ไป[และ]ไป]ในการผ่าน สิ่งนี้ไร้ประโยชน์ แต่ไม่เป็นอันตราย อย่างไรก็ตามหากไม่มีเครื่องหมายอัญประกาศเชลล์จะขยายวงเล็บถ้ามีไฟล์ที่มีชื่อตัวอักษรตัวพิมพ์ใหญ่หนึ่งตัวในไดเรกทอรีปัจจุบัน
Gilles 'หยุดความชั่วร้าย'

0

ฉันใช้สิ่งนี้เป็นความท้าทายแบบหนึ่งบรรทัด :) ขั้นแรกสร้างกรณีทดสอบ:

$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar     aBar.txt    aeVe.txt    afoo.txt    eVe     foo

ฉันจะใช้findเพื่อจุดไดเรกทอรีที่มีตัวอักษรพิมพ์ใหญ่และแล้ว downcase พวกเขาผ่านทาง การเดาใช้เป็นบิตแฮ็ค แต่หัวของฉันจะระเบิดเสมอเมื่อฉันพยายามหลบหนีสิ่งต่าง ๆโดยตรงsh -c 'mv {} echo {} | tr [:upper:] [:lower:]'sh -cfind

$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt    aeVe.txt    afoo.txt    bar     eve     foo

คำเตือน: วิธีนี้ไม่ได้ตรวจสอบว่าการลดขนาดจะนำไปสู่การชนหรือไม่!


การตรวจสอบการชนเป็นเรื่องง่าย: mv -i. ปัญหาใหญ่คือคุณไม่ได้ใช้การอ้างอิงที่เหมาะสมดังนั้นคำสั่งของคุณจะล้มเหลวหากมีอักขระพิเศษ (ช่องว่างหรือ\[*?) ที่ใดก็ได้ในชื่อ มีจุดของการใช้ไม่ได้findเว้นแต่ recursing และจากนั้นคุณต้องfind -depthและจะต้องเป็น-path -nameดูคำตอบของฉันสำหรับตัวอย่างการทำงาน
Gilles 'หยุดความชั่วร้าย'

@Giles ขอบคุณ! ฉันเห็นคุณmv -iหลังจากเขียนสิ่งนี้ จุดที่ดีกับข้อความ ...
Janus

0

find -execdir| เปลี่ยนชื่อ

นี่จะเป็นวิธีที่ดีที่สุดในการทำถ้าไม่ใช่เพราะความบ้าคลั่งของเส้นทางญาติเพราะมันหลีกเลี่ยง Perl regex fu เพื่อทำตามชื่อฐานเท่านั้น:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;

-execdirก่อนcdเข้าสู่ไดเรกทอรีก่อนที่จะดำเนินการเฉพาะในฐาน

น่าเสียดายที่ฉันไม่สามารถกำจัดPATHส่วนที่แฮ็กได้find -execdirปฏิเสธที่จะทำอะไรถ้าคุณมีเส้นทางญาติในPATH... : /ubuntu/621132/why-using-the-execdir-action- เป็นที่ไม่ปลอดภัยสำหรับไดเรกทอรีซึ่งเป็น-in-the-เส้นทาง / 1109378 # 1109378

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