ฉันจะใช้การเปลี่ยนชื่อเพื่อเปลี่ยนชื่อซ้ำทุก ๆ ครั้งเป็นตัวพิมพ์ใหญ่ได้อย่างไร


11

ฉันต้องการเปลี่ยนชื่อไฟล์และโฟลเดอร์ทั้งหมด (โฟลเดอร์ย่อย) ซ้ำ ๆ ให้เป็นตัวพิมพ์ใหญ่

ฉันพบสคริปต์บางอย่างที่จะทำให้เป็นตัวพิมพ์เล็ก แต่ฉันไม่ทราบวิธีการเปลี่ยนสคริปต์ดังนั้นจะทำแบบอื่น ๆ (ล่างเป็นบน)

สคริปต์ที่ฉันพบและใช้งานได้สำหรับตัวพิมพ์เล็ก แต่ฉันไม่รู้วิธีแก้ไขคือ:

rename 'y/A-Z/a-z/' *

man renameมันมาจาก


โดยไม่ต้องรู้อะไรเกี่ยวกับคำสั่งเปลี่ยนชื่อฉันสงสัยว่าถ้าคุณลองrename 'y/a-z/A-Z/' *คุณจะได้รับสิ่งที่คุณต้องการ ระวังที่คุณทดสอบผ่าน
Warwick

มันไม่ได้เกิดซ้ำ (เพราะตัวแรกไม่ได้ ... ) แต่ใช้งานได้ ฉันไม่สามารถเข้าใจได้ว่าทำไมฉันถึงไม่รู้สึกผิดที่คิดผิด :)
jnhghy - Alexandru Jantea

ฉันคิดว่านั่นเป็นเพราะคุณภาพของคำตอบของ Gilles มันจะดีถ้าคุณยอมรับคำตอบของเขาตามที่ต้องการ สมบูรณ์กว่าของฉันมากและอธิบายตัวเลือกของคุณ (และวิธีการทำงานทั้งหมด) ขอบคุณ
Warwick

คำตอบ:


8

โปรดทราบว่าคุณกำลังใช้งานสคริปต์ Perl ที่renameจัดทำโดย Debian และตราสารอนุพันธ์ (Ubuntu, Mint, …) ลีนุกซ์รุ่นอื่น ๆ จัดส่งคำสั่งที่แตกต่างอย่างสิ้นเชิงและมีประโยชน์น้อยกว่าอย่างrenameมาก

y/A-Z/a-z/แปลอักขระแต่ละตัวในช่วงที่Aผ่านZเป็นอักขระที่ตรงกันในช่วงaถึงzเช่นตัวอักษร ASCII ตัวพิมพ์ใหญ่เป็นตัวอักษรตัวพิมพ์เล็กที่สอดคล้องกัน y/a-z/A-Z/เพื่อดำเนินการแปลตรงข้ามใช้ อีกวิธีในการเขียนคำสั่งเดียวกันคือrename '$_ = uc($_)' *ucคือฟังก์ชันu pper c ase และrenameคำสั่งเปลี่ยนชื่อไฟล์ตามการแปลงที่ทำกับ$_ตัวแปร

rename '…' *เปลี่ยนชื่อไฟล์ในไดเรกทอรีปัจจุบันเท่านั้นเพราะนั่นคือสิ่งที่*ตรงกัน ไฟล์ Dot (ไฟล์ที่มีชื่อขึ้นต้นด้วย.) จะถูกข้ามเช่นกัน

หากคุณต้องการเปลี่ยนชื่อไฟล์ในไดเรกทอรีปัจจุบันและในไดเรกทอรีย่อยซ้ำคุณสามารถใช้findคำสั่งเพื่อสำรวจไดเรกทอรีปัจจุบันซ้ำ มีความยากอยู่ที่นี่: ถ้าคุณโทรrenameสิ่งนี้จะเปลี่ยนชื่อทั้งไดเรกทอรีและส่วนชื่อฐาน หากคุณโทรหาrenameไดเรกทอรีก่อนที่จะเรียกซ้ำ ( find -exec rename … {} \;) findจะสับสนเพราะพบไดเรกทอรี แต่ไดเรกทอรีนั้นไม่มีอยู่อีกต่อไปตามเวลาที่มันพยายามสืบหามัน คุณสามารถทำงานรอบนี้โดยบอกว่าfindการสำรวจไดเรกทอรีก่อนที่จะกระทำกับมัน แต่แล้วคุณจะจบลงด้วยความพยายามที่จะเปลี่ยนชื่อfoo/barไปFOO/BARแต่ไดเรกทอรีFOOไม่อยู่

วิธีง่ายๆในการหลีกเลี่ยงปัญหานี้คือการทำให้คำสั่งการเปลี่ยนชื่อดำเนินการเฉพาะในส่วนชื่อฐานของเส้นทาง การแสดงออกปกติตรงกับส่วนสุดท้ายของเส้นทางที่ไม่ได้มี([^/]*\Z)/

find . -depth -exec rename 's!([^/]*\Z)!uc($1)!e' {} +

shell zsh นำเสนอคุณสมบัติที่สะดวกกว่าสำหรับการเปลี่ยนชื่อ - ยิ่งเป็นความลับยิ่งกว่า Perl แต่ผู้ทดสอบและมักจะเขียนง่ายกว่า

ฟังก์ชั่นzmvเปลี่ยนชื่อไฟล์ตามรูปแบบ เรียกใช้autoload -U zmvหนึ่งครั้งเพื่อเปิดใช้งาน (ใส่บรรทัดนี้ในของคุณ.zshrc)

ในอาร์กิวเมนต์แรกzmv(รูปแบบที่จะเปลี่ยน), คุณสามารถใช้ zsh ที่มีประสิทธิภาพของรูปแบบสัญลักษณ์แทน ในอาร์กิวเมนต์ที่สองที่จะzmv(ข้อความทดแทน), คุณสามารถใช้มันขยายตัวพารามิเตอร์คุณสมบัติรวมทั้งการปรับเปลี่ยนประวัติศาสตร์

zmv -w '**/*' '$1$2:u'

คำอธิบาย:

  • -w - กำหนดตัวแปรตัวเลขให้กับแต่ละรูปแบบของสัญลักษณ์แทนโดยอัตโนมัติ
  • **/*- ไฟล์ทั้งหมดในไดเรกทอรีย่อยซ้ำ ( **/ตรงกับ 0, 1 หรือมากกว่าระดับของไดเรกทอรีย่อย)
  • $1 - ตัวแปรตัวเลขตัวแรกตรงกับส่วนไดเรกทอรีของแต่ละเส้นทาง
  • $2:u- ตัวแปรตัวเลขตัวที่สองตรงกับส่วนชื่อฐานของแต่ละพา ธ พร้อม:uตัวปรับเพื่อแปลงค่าให้เป็นตัวพิมพ์ใหญ่

ในฐานะโบนัสที่เพิ่มเข้ามาสิ่งนี้จะคำนึงถึงการตั้งค่าสถานที่โดยรอบ

หากคุณไม่แน่ใจเกี่ยวกับzmvคำสั่งที่คุณเขียนคุณสามารถส่ง-nตัวเลือกเพื่อพิมพ์สิ่งที่คำสั่งจะทำและไม่เปลี่ยนแปลงอะไร ตรวจสอบผลลัพธ์และหากเป็นไปตามที่คุณต้องการให้รันคำสั่งอีกครั้งโดยไม่ต้อง-nทำอะไร


5

ถูกขโมย (มีการแก้ไขเล็กน้อย) จาก Gilles โพสต์ที่นี่

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


สิ่งนี้ไม่ได้กระทำซ้ำ ๆ
Gilles 'ดังนั้นหยุดความชั่วร้าย'

จริง ฉันควรอ่านคำถามอย่างถูกต้อง ฉันไม่สามารถเข้าถึงคำสั่งเปลี่ยนชื่อ แต่ฉันเชื่อว่าสิ่งนี้จะทำงานซ้ำfind <dir> -exec rename 'y/a-z/A-Z/' {} \;
Warwick

มันซับซ้อนกว่านั้นเล็กน้อยเนื่องจากคุณเปลี่ยนชื่อไดเรกทอรีในขณะที่findเรียกใช้ซ้ำ
Gilles 'หยุดความชั่วร้าย'

@Gilles - ตกลง หลังจากทำการค้นคว้าเล็กน้อยดูเหมือนว่าฉันต้องเพิ่มตัวเลือก -depth เพื่อค้นหาชื่อไดเรกทอรีที่จะจัดการล่าสุด ดังนั้นfind <dir> -depth -exec rename 'y/a-z/A-Z/' {} \;ควรจัดการกับปัญหาการเปลี่ยนชื่อไดเรกทอรี แก้ไข?
Warwick

ไม่นั่นยังใช้งานไม่ได้เพราะrenameการเปลี่ยนแปลงเช่นfoo/barไปFOO/BARและFOOไม่มีอยู่ ณ จุดนั้น
Gilles 'หยุดความชั่วร้าย'

2

ผมอยากให้ทุกคนโดยตรงผู้ที่ยังคงมีการเชื่อมโยงกับคำตอบนี้จะเป็นคำตอบที่ดีเยี่ยม Guiles Quernot findให้กับคำถามนี้ซึ่งไม่จำเป็นต้อง

คำสั่งผลลัพธ์จะเป็น:

shopt -s globstar
rename -n 'y/a-z/A-Z/' **

แต่ก่อนที่จะทำงานโปรดอ่านคำตอบที่เชื่อมโยงสำหรับ caveats เกี่ยวกับรุ่นทุบตีเก่า

ในที่สุดในกรณีที่มีคนสงสัยว่าy///คำสั่งทำperl regexอะไร นี่คือการเชื่อมโยงไปยังเอกสารที่เกี่ยวข้อง


1

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

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

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

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

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


0

ลองสิ่งนี้หลังจากย้ายไปยังไดเรกทอรีที่คุณต้องการเปลี่ยนชื่อไฟล์:

for word in `ls -ltr |tail -n +2 |awk '{print $9}'`
do
  a=$(echo $word | tr '[a-z]' '[A-Z]')
  mv $word $a
  echo "Done Successfully"
done

อย่าแยกผลลัพธ์ของคำสั่ง ls (และทำไมในโลกที่คุณจะทำงานls -lเพียงเพื่อตัดคอลัมน์อื่น ๆ กว่าชื่อ?) และใช้คำพูดสองรอบแทนตัวแปร รหัสของคุณซับซ้อนเกินไปและแบ่งชื่อไฟล์ที่มีช่องว่างและอักขระพิเศษอื่น ๆ ใช้findหรือเรียก**/เก็บเงินคืนในไดเรกทอรีย่อยเอาต์พุตของlsมีไว้สำหรับการบริโภคของมนุษย์เท่านั้น
Gilles 'หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.