ฉันมีไฟล์จำนวนมากที่มี.abcนามสกุลและต้องการเปลี่ยนเป็น.edefg
วิธีการทำจากบรรทัดคำสั่ง?
ฉันมีโฟลเดอร์รูทที่มีโฟลเดอร์ย่อยมากมายดังนั้นโซลูชันควรทำงานซ้ำ
ฉันมีไฟล์จำนวนมากที่มี.abcนามสกุลและต้องการเปลี่ยนเป็น.edefg
วิธีการทำจากบรรทัดคำสั่ง?
ฉันมีโฟลเดอร์รูทที่มีโฟลเดอร์ย่อยมากมายดังนั้นโซลูชันควรทำงานซ้ำ
คำตอบ:
วิธีการพกพา (ซึ่งจะทำงานบนระบบที่สอดคล้องกับ POSIX ใด ๆ ):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
ใน bash4 คุณสามารถใช้ globstar เพื่อรับ globs ซ้ำ (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
renameคำสั่ง(perl) ใน Ubuntu สามารถเปลี่ยนชื่อไฟล์โดยใช้ไวยากรณ์การแสดงออกปกติของ Perl ซึ่งคุณสามารถรวมกับ globstar หรือfind:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
${1%.abc}...
sh -c อาร์กิวเมนต์แรกได้รับมอบหมายให้ $ 0 และข้อโต้แย้งใด ๆ ที่เหลือได้รับมอบหมายให้พารามิเตอร์ตำแหน่ง ดังนั้น_คืออาร์กิวเมนต์หุ่นและ '{}' sh -cเป็นอาร์กิวเมนต์ที่ตำแหน่งแรกที่
สิ่งนี้จะทำงานที่จำเป็นหากไฟล์ทั้งหมดอยู่ในโฟลเดอร์เดียวกัน
rename 's/.abc$/.edefg/' *.abc
หากต้องการเปลี่ยนชื่อไฟล์ให้ใช้สิ่งนี้ซ้ำ:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcใน Bash รุ่นทันสมัย
sจุดเริ่มต้นและตัวเลือกอื่น ๆ ที่ฉันสามารถใช้ได้ในนั้น ขอบคุณมาก!
ปัญหาอย่างหนึ่งของการเปลี่ยนชื่อแบบเรียกซ้ำคือวิธีใดก็ตามที่คุณใช้เพื่อค้นหาไฟล์มันจะส่งผ่านพา ธ ทั้งหมดไปที่renameไม่ใช่แค่ชื่อไฟล์ ทำให้ยากที่จะทำการเปลี่ยนชื่อที่ซับซ้อนในโฟลเดอร์ซ้อนกัน
ผมใช้findของ-execdirการดำเนินการเพื่อแก้ปัญหานี้ หากคุณใช้-execdirแทน-execคำสั่งที่ระบุจะถูกเรียกใช้จากไดเรกทอรีย่อยที่มีไฟล์ที่ตรงกัน ดังนั้นแทนที่จะผ่านเส้นทางทั้งไปก็เพียงผ่านrename ./filenameทำให้การเขียน regex ง่ายขึ้น
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
ในรายละเอียด:
-type f หมายถึงค้นหาเฉพาะไฟล์ไม่ใช่ไดเรกทอรี-name '*.abc' หมายถึงการจับคู่ชื่อไฟล์ที่ลงท้ายด้วย. abc เท่านั้น'{}'เป็นตัวยึดตำแหน่งที่ทำเครื่องหมายสถานที่ที่-execdirจะแทรกเส้นทางที่พบ ต้องการอัญประกาศเดี่ยวเพื่ออนุญาตให้จัดการกับชื่อไฟล์ด้วยช่องว่างและอักขระเชลล์-typeและ-nameเป็นอักขระต่อเนื่องของ bash ฉันใช้มันเพื่อทำให้ตัวอย่างนี้อ่านง่ายขึ้น แต่พวกเขาไม่จำเป็นถ้าคุณทำให้คำสั่งทั้งหมดในบรรทัดเดียว-execdirบรรทัด -execdirมันจะมีที่จะหลบหนีอัฒภาคซึ่งยุติการทำงานคำสั่งโดย สนุก!คำอธิบายของ regex:
s/ เริ่มต้นของ regex\.\/จับคู่กับ. / that -execdir ผ่านเข้าไปใช้ \ เพื่อหลีกเลี่ยง และ / metacharacters (หมายเหตุ: ส่วนนี้จะแตกต่างกันไปขึ้นอยู่กับรุ่นของfindคุณดูความคิดเห็นจากผู้ใช้ @apollo)(.+)ตรงกับชื่อไฟล์ วงเล็บจับการแข่งขันเพื่อใช้ในภายหลัง\.abc หนีจุดจับคู่ abc$ สมอการแข่งขันที่ส่วนท้ายของสตริง
/ ทำเครื่องหมายจุดสิ้นสุดของส่วน "จับคู่" ของ regex และจุดเริ่มต้นของส่วน "แทนที่"
version1_ เพิ่มข้อความนี้ให้กับทุกชื่อไฟล์
$1อ้างอิงชื่อไฟล์ที่มีอยู่เพราะเราจับมันด้วยเครื่องหมายวงเล็บ หากคุณใช้วงเล็บหลายชุดในส่วน "จับคู่" คุณสามารถอ้างอิงได้ที่นี่โดยใช้ $ 2, $ 3, ฯลฯ.abcชื่อไฟล์ใหม่จะลงท้ายด้วย. abc ไม่จำเป็นต้องหลบหลีกตัวชี้จุดที่นี่ในส่วน "แทนที่"/ ในตอนท้ายของ regexก่อน
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
หลังจาก
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
คำแนะนำ: renameตัวเลือก -n มีประโยชน์ มันทำงานแบบแห้งและแสดงให้คุณเห็นว่าชื่อจะเปลี่ยนไป แต่ไม่ได้ทำการเปลี่ยนแปลงใด ๆ
--execdirไม่ผ่านในการนำ./เพื่อให้\.\/ส่วนใน regex สามารถละเว้น อาจเป็นเพราะฉันใช้ OSX ไม่ใช่ Ubuntu
วิธีพกพาอื่น:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
lsนอกจากนี้ยังดูรายการเกี่ยวกับเหตุผลที่คุณไม่ควรแยก
แก้ไข: ถ้าคุณต้องใช้ชื่อไฟล์ไวยากรณ์ของคุณจะเป็น:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
นี่คือสิ่งที่ฉันทำและทำงานในแบบที่ฉันต้องการ ฉันใช้mvคำสั่ง ฉันมีหลาย.3gpไฟล์และฉันต้องการเปลี่ยนชื่อพวกเขาทั้งหมดเป็น.mp4
นี่เป็นตัวย่อสำหรับมัน:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
ซึ่งเพียงสแกนผ่านไดเรกทอรีปัจจุบันรับไฟล์. 3gp ทั้งหมดจากนั้นเปลี่ยนชื่อ (โดยใช้ mv) เป็น ren-name_of_file.mp4
file.3gpเป็นfile.3gp.mp4ซึ่งอาจไม่ใช่สิ่งที่คนส่วนใหญ่ต้องการ
.3gpหรือ.mp4นี่เป็นเพียงเพื่อวัตถุประสงค์ภาพประกอบ
basename "$i" .mp4เพื่อลบส่วนขยายก่อนหน้าแทน "ren- $ i.mp4"
ฉันพบวิธีง่ายๆในการบรรลุเป้าหมายนี้ หากต้องการเปลี่ยนนามสกุลของไฟล์จำนวนมากจาก jpg เป็น pdf ให้ใช้:
for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
ฉันจะใช้คำสั่ง mmv จากแพ็คเกจชื่อเดียวกัน :
mmv ';*.abc' '#1#2.edefg'
;ตรงกับศูนย์หรือมากกว่า*/และสอดคล้องกับ#1ในการเปลี่ยน สอดคล้องกับ* #2รุ่นที่ไม่ใช่แบบเรียกซ้ำจะเป็น
mmv '*.abc' '#1.edefg'
เปลี่ยนชื่อไฟล์และไดเรกทอรีด้วย find -execdir | rename
หากคุณจะเปลี่ยนชื่อทั้งไฟล์และไดเรกทอรีไม่ใช่เพียงแค่คำต่อท้ายนี่เป็นรูปแบบที่ดี:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find . -depth -execdir rename 's/findme/replaceme/' '{}' \;
น่ากลัว-execdirตัวเลือกที่ไม่ได้cdลงในไดเรกทอรีก่อนดำเนินการคำสั่งซึ่งแตกต่างจากrename-exec
-depth ตรวจสอบให้แน่ใจว่าการเปลี่ยนชื่อเกิดขึ้นครั้งแรกกับเด็ก ๆ และจากนั้นในผู้ปกครองเพื่อป้องกันปัญหาที่อาจเกิดขึ้นกับไดเรกทอรีหลักที่ขาดหายไป
-execdir จำเป็นต้องมีเนื่องจากการเปลี่ยนชื่อเล่นได้ไม่ดีกับเส้นทางเข้าที่ไม่ใช่ชื่อไฟล์เช่นต่อไปนี้ล้มเหลว:
rename 's/findme/replaceme/g' acc/acc
การPATHแฮ็คเป็นสิ่งจำเป็นเนื่องจาก-execdirมีข้อเสียเปรียบที่น่ารำคาญอย่างหนึ่ง: findมีความเห็นอย่างมากและปฏิเสธที่จะทำทุกอย่าง-execdirหากคุณมีเส้นทางญาติในPATHตัวแปรสภาพแวดล้อมของคุณเช่น./node_modules/.binล้มเหลวด้วย:
find: พา ธ สัมพัทธ์ './node_modules/.bin' รวมอยู่ในตัวแปรสภาพแวดล้อม PATH ซึ่งไม่ปลอดภัยเมื่อใช้ร่วมกับการดำเนินการ -execdir ของการค้นหา โปรดลบรายการนั้นออกจาก $ PATH
ดูเพิ่มเติม: เหตุใดการใช้การกระทำ '-execdir' จึงไม่ปลอดภัยสำหรับไดเรกทอรีที่อยู่ใน PATH
-execdirเป็น GNU พบส่วนขยายไปยัง POSIX renameเป็นภาษา Perl และมาจากrenameแพ็คเกจ ทดสอบใน Ubuntu 18.10
เปลี่ยนชื่อวิธีแก้ปัญหา lookahead
หากเส้นทางอินพุตของคุณไม่ได้มาจากfindหรือหากคุณมีความรำคาญในเส้นทางสัมพัทธ์เพียงพอเราสามารถใช้ Perl lookahead เพื่อเปลี่ยนชื่อไดเรกทอรีอย่างปลอดภัยใน:
git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
ฉันไม่พบอะนาล็อกที่สะดวกสำหรับ-execdirด้วยxargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
sort -rเป็นสิ่งจำเป็นเพื่อให้มั่นใจว่าไฟล์มาหลังจากไดเรกทอรีของตนตั้งแต่เส้นทางอีกต่อมาหลังจากที่คนสั้นด้วยคำนำหน้าเดียวกัน