ฉันมีไฟล์จำนวนมากที่มี.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
เป็นสิ่งจำเป็นเพื่อให้มั่นใจว่าไฟล์มาหลังจากไดเรกทอรีของตนตั้งแต่เส้นทางอีกต่อมาหลังจากที่คนสั้นด้วยคำนำหน้าเดียวกัน