ฉันจะเปลี่ยนชื่อนามสกุลสำหรับกลุ่มของไฟล์ได้อย่างไร


479

ในไดเรกทอรีฉันมี*.htmlไฟล์มากมาย ฉันต้องการเปลี่ยนชื่อพวกเขาทั้งหมดเป็น*.txt

ฉันจะทำสิ่งนั้นได้อย่างไร ฉันใช้เปลือก bash

คำตอบ:


382

สำหรับวิธีการแก้ปัญหาที่ดีกว่า (มีฟังก์ชันการทำงานทุบตีเท่านั้นเมื่อเทียบกับสายภายนอก) ดูหนึ่งในคำตอบอื่น


ต่อไปนี้จะทำและไม่ต้องการให้ระบบมีrenameโปรแกรม (แม้ว่าคุณมักจะมีสิ่งนี้ในระบบ):

for file in *.html; do
    mv "$file" "$(basename "$file" .html).txt"
done

แก้ไข:ตามที่ระบุไว้ในความคิดเห็นนี้ไม่ทำงานสำหรับชื่อไฟล์ที่มีช่องว่างในพวกเขาโดยไม่ต้องอ้างอิงที่เหมาะสม (ตอนนี้เพิ่มด้านบน) เมื่อทำงานอย่างหมดจดกับไฟล์ของคุณที่คุณรู้ว่าไม่มีช่องว่างในชื่อไฟล์สิ่งนี้จะใช้ได้ แต่เมื่อใดก็ตามที่คุณเขียนบางสิ่งที่อาจนำมาใช้ซ้ำในภายหลังอย่าข้ามการอ้างอิงที่เหมาะสม


47
อีกทางเลือกหนึ่งโดยไม่ต้องมี basename & ด้วยเครื่องหมายคำพูด: mv "$ {file}" "$ {file /%. html / .txt}" (ดู man bash, การขยายพารามิเตอร์เพื่อดูรายละเอียด)
Rodrigo Queiro

7
จะดีก็ต่อเมื่อไฟล์ทั้งหมดอยู่ในไดเรกทอรีปัจจุบันแน่นอนเพราะ basename จะตัดส่วนของชื่อพา ธ ออก เพียงแค่ 'ระวัง'!
Jonathan Leffler

6
วิธีนี้ไม่ดีไม่เพียงเพราะมันช้า แต่เพราะมันใช้ไม่ได้กับชื่อไฟล์ที่มีช่องว่าง คุณควรทำใบเสนอราคาที่ถูกต้องในสคริปต์ทุบตี mv "$ file" "$ (basename" $ ​​file ".html)". txt จะดีกว่ามาก แต่ถึงกระนั้น mv "$ files" "$ {files% .html} .txt" ก็ดีกว่ามาก
BalázsPozsár

8
ในหน้าต่างที่คุณเพิ่งทำren *.a *.b
Muhammad Umer

2
อย่างน้อยที่สุดให้ใช้ POSIX ที่ระบุ$()แทนไวยากรณ์ backtick ดั้งเดิม ปรับปรุงความสามารถในการอ่านและทำให้ไวยากรณ์มีความคลุมเครือน้อยลงเมื่อคุณมีอักขระที่ต้องใช้เครื่องหมายแบ็กสแลชเพื่อให้เป็นตัวอักษรในการทดแทนคำสั่งด้วยตัวหลัง
ชาร์ลส์ดัฟฟี่

668

หากใช้ bash คุณไม่จำเป็นต้องใช้คำสั่งภายนอกเช่น sed, basename, rename, expr ฯลฯ

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done

12
และหากคุณไม่ทราบนามสกุลไฟล์ที่คุณสามารถใช้ได้"${file%.*}.txt"แต่สิ่งนี้อาจเป็นอันตรายสำหรับไฟล์ที่ไม่มีนามสกุลไฟล์เลย
Jess

1
หมายเหตุถึงใครก็ตามที่มีปัญหาในการทำงานเช่นนี้: สังเกตว่าไม่มี$การดัดผมด้านใน!
doug65536

5
ฉันต้องการวิธีการที่ชื่นชอบถาวร / คั่นคำตอบนี้ฉันไม่เคยจำไวยากรณ์ที่แน่นอนและฉันก็จบลงด้วยการ googling มัน
boliva

7
@danip โครงสร้างการสร้างเครื่องหมายภายในวงเล็บปิดอักขระที่ส่วนท้าย นอกจากนี้ยังมีโครงสร้างแฮชภายในวงเล็บที่ตัดอักขระออกจากจุดเริ่มต้น ตรวจสอบได้ที่: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2

4
คำตอบการแลกเปลี่ยนสแต็กอื่น (ที่ฉันหาไม่พบ!) แนะนำสิ่งนี้ แต่ใช้--"โอเปอเรเตอร์": mv - "$ file" "$ {file% .html} .txt" โอเปอเรเตอร์นั้นป้องกันชื่อไฟล์ที่ขึ้นต้นด้วย a '-' จากการแยกวิเคราะห์โดย mv เป็นอาร์กิวเมนต์
rcreswick

191
rename 's/\.html$/\.txt/' *.html

ทำสิ่งที่คุณต้องการ


ฉันไม่คิดว่าคุณสามารถใช้ regex ที่แท้จริงในการทุบตีตามที่คุณแนะนำ - คุณใช้เชลล์ไหน?
DaveR

1
ฉันใช้เครื่องเทอร์มินัล Mac
bmw0128

นี่คือ man page สำหรับเวอร์ชันการเปลี่ยนชื่อบน Ubuntu: unixhelp.ed.ac.uk/CGI/man-cgi?rename
Amber

การเปลี่ยนชื่อเป็นคำสั่งในบางระบบ ฉันมีสคริปต์ Perl (มีพื้นเพมาจากหนังสือ Camel เล่มแรก) ที่ทำงานได้ นอกจากนี้ยังมีโปรแกรม GNU ที่มีชื่อเดียวกันกับที่ใช้ในงานเดียวกัน Mac ของฉันไม่มีคำสั่ง 'เปลี่ยนชื่อ' ที่ระบบจัดหาให้หรือไม่ได้อยู่ใน PATH ของฉัน (ซึ่งครอบคลุมพอสมควร)
Jonathan Leffler

มีสูตรการเปลี่ยนชื่อใน Homebrew
revprez

112

สิ่งนี้ใช้ได้กับฉันใน OSX จาก. txt ถึง. txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;

4
ทำงานได้ดีใน linux เช่นกัน
Diziet

มันนอกเหนือจากจุด แต่จะไปจาก.txtเพื่อ.txt_bakคุณเพียงแค่ต้อง concatenate _bak;)
corwin.amber

3
นี่เป็นสิ่งที่ดีสำหรับการเปลี่ยนชื่อซ้ำ ๆ
leachryanb

ที่ดี! (ภายใต้ Ubuntu 16.04) กรณีการใช้งานจริงของฉันเปลี่ยนชื่อ.scssเป็น.sass(หลังจากการแปลงในสถานที่ ... ):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Frank Nocke

2
สิ่งนี้ใช้ได้กับไฟล์ 6,000 ไฟล์เปลี่ยนชื่อรายงานว่า "รายการอาร์กิวเมนต์ยาวเกินไป"
Tony Cronin

94

คุณต้องการใช้rename:

rename -S .html .txt *.html

นี้ไม่ตรงกับสิ่งที่คุณต้องการ - มันจะเปลี่ยนนามสกุลจาก.htmlไปสำหรับไฟล์ทั้งหมดที่ตรงกัน.txt*.html

หมายเหตุ: Greg Hewgill ชี้ให้เห็นอย่างถูกต้องว่านี่ไม่ใช่ bash builtin; และเป็นคำสั่งแยก Linux หากคุณต้องการบางสิ่งบน Linux สิ่งนี้ก็ใช้ได้ดี หากคุณต้องการสิ่งที่ข้ามแพลตฟอร์มมากขึ้นลองดูคำตอบอย่างใดอย่างหนึ่ง


7
แม้ว่านี่จะเป็นวิธีแก้ปัญหาที่ดี แต่renameโปรแกรมไม่เกี่ยวข้องbashและไม่สามารถใช้ได้ในทุกแพลตฟอร์ม ฉันเห็นมันบน Linux เท่านั้น
Greg Hewgill

15
"$ rename .html .txt * .html" ส่งผลให้ ... เกิดข้อผิดพลาดทางไวยากรณ์ที่ (eval 1) บรรทัด 1 ใกล้กับ "."
เหลืองอำพัน

8
ไวยากรณ์ที่ถูกต้องคือrename -S .html .text *.htmlที่-Sย่อมาจาก--subst-all
Marek Sebera

8
ชงติดตั้งเปลี่ยนชื่อ
นิค

4
@GregHewgill เปลี่ยนชื่อพร้อมใช้งานสำหรับ Mac OS ด้วย
HomeBrew



9

นี่เป็นทางออกที่ลื่นที่สุดที่ฉันพบว่าทำงานได้บน OSX และ Linux และมันก็ทำงานได้ดีกับ git เช่นกัน!

find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

และด้วยคอมไพล์:

find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;


8

นี่คือตัวอย่างของคำสั่งเปลี่ยนชื่อ:

rename -n s/\.htm$/\.html/’ *.htm

-n หมายความว่าเป็นการทดสอบการทำงานและจะไม่เปลี่ยนแปลงไฟล์ใด ๆ มันจะแสดงรายการของไฟล์ที่จะถูกเปลี่ยนชื่อหากคุณลบ -n ในกรณีข้างต้นมันจะแปลงไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันจากนามสกุลไฟล์ของ. htm เป็น. html

หากผลลัพธ์ของการทดสอบการทำงานด้านบนดูดีแล้วคุณก็สามารถเรียกใช้เวอร์ชั่นสุดท้ายได้:

rename -v s/\.htm$/\.html/’ *.htm

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

$ rename -v 's/\.htm$/\.html/' *.htm
3.htm renamed as 3.html
4.htm renamed as 4.html
5.htm renamed as 5.html

ส่วนที่อยู่ตรงกลางตรงกลางคือการแทนที่ Perl ด้วยนิพจน์ปกติโดยไฮไลต์ด้านล่าง:

rename -v s/\.htm$/\.html/’ *.htm

6

คำถามนี้พูดถึง Bash อย่างชัดเจน แต่ถ้าคุณมี ZSH ให้ใช้งานมันก็ค่อนข้างง่าย:

zmv '(*).*' '$1.txt'

หากคุณได้รับzsh: command not found: zmvแล้วเพียงแค่เรียกใช้:

autoload -U zmv

จากนั้นลองอีกครั้ง

ขอบคุณบทความต้นฉบับนี้สำหรับคำแนะนำเกี่ยวกับ zmv


4

หลังจากการรวบรวมข้อมูลเว็บไซต์ของคนอื่นฉันจบลงด้วยไฟล์หลายพันไฟล์ที่ขาดนามสกุล. html ข้ามไดเรกทอรีย่อยกว้าง ๆ

หากต้องการเปลี่ยนชื่อพวกเขาทั้งหมดในนัดเดียวยกเว้นไฟล์ที่มีนามสกุล. html อยู่แล้ว (ส่วนใหญ่ไม่มีเลย) สิ่งนี้ใช้ได้กับฉัน:

cd wwwroot
find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING

ในกรณีของ OP ฉันอาจแก้ไขเล็กน้อยเพื่อเปลี่ยนชื่อไฟล์ * .txt เช่น:

find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 

พัง (Hammertime!):

-iname * .txt
- หมายถึงพิจารณาเฉพาะไฟล์ที่ลงท้ายด้วย. txt แล้ว

mv -iv "{} {txt, HTML}." - เมื่อพบ {. ชื่อไฟล์% *} ผ่าน {} เป็นชื่อไฟล์, $ สารสกัดจาก basename โดยไม่ต้องขยายใด ๆ ในรูปแบบพารามิเตอร์mv bashใช้ {txt, html} เพื่อเขียนซ้ำเป็นพารามิเตอร์สองตัวดังนั้นคำสั่งสุดท้ายจะทำงานเป็น:mv -iv "filename.txt" "filename.html"

แก้ไขตามต้องการ: จัดการกับช่องว่างในชื่อไฟล์


4

คำสั่งmmvดูเหมือนว่าจะทำภารกิจนี้ได้อย่างมีประสิทธิภาพมากในการเป็นจำนวนมากของไฟล์ (นับหมื่นในครั้งที่สอง) ตัวอย่างเช่นหากต้องการเปลี่ยนชื่อ.xmlไฟล์ทั้งหมดเป็นไฟล์ให้.htmlใช้สิ่งนี้:

mmv ";*.xml" "#1#2.html"

;จะตรงกับเส้นทางที่*จะตรงกับชื่อไฟล์และสิ่งเหล่านี้จะเรียกว่า#1และ#2ในการเปลี่ยนชื่อ

คำตอบที่อ้างอิงจากexecไปป์หรือช้าเกินไปหรือล้มเหลวในไฟล์จำนวนมาก



3

สายไปงานเลี้ยงเล็กน้อย คุณสามารถทำได้ด้วย xargs:

ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}

หรือถ้าไฟล์ทั้งหมดของคุณอยู่ในบางโฟลเดอร์

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}

3
ครั้งที่ทำไม่ได้แยก lsคำสั่งนี้ไร้สาระ: มันใช้กับ glob lsแทนการใช้ glob โดยตรง สิ่งนี้จะแตกด้วยชื่อไฟล์ที่มีช่องว่างเครื่องหมายคำพูดและ (เนื่องจากไม่มีเครื่องหมายคำพูด) อักขระ glob
gniourf_gniourf

FYI บทความที่เชื่อมโยงของคุณมีหมายเหตุที่อัปเดตซึ่งระบุว่าไฟล์ "shell escapes" รุ่นใหม่ที่ถูกต้องหากพิมพ์ไปยังเทอร์มินัล ' ประเด็นของคุณยังคงเป็นกฎง่ายๆ
Katastic Voyage

3

นี่เป็นวิธีที่ดีในการแก้ไขส่วนขยายหลายรายการพร้อมกัน:

for fname in *.{mp4,avi}
do
   mv -v "$fname" "${fname%.???}.mkv"
done

หมายเหตุ: ระวังขนาดส่วนขยายให้เท่ากัน (the ???)



2

หากคุณต้องการ PERL มีเป็น Perl สคริปต์สั้น ๆ (เขียนโดยแลร์รี่วอลล์, ผู้สร้าง PERL) ที่จะทำสิ่งที่คุณต้องการที่นี่: tips.webdesign10.com/files/rename.pl.txt

สำหรับตัวอย่างของคุณต่อไปนี้ควรทำเคล็ดลับ:

rename.pl 's/html/txt/' *.html

2
คำถามนี้ได้รับการตอบแล้วและยอมรับมานานแล้วและดูเหมือนว่าคำตอบของคุณจะนำอะไรที่มากกว่าสิ่งที่พูดไปแล้ว
ChristopheLec

1
+1 เนื่องจากเป็นสคริปต์ Larry Wall (แก้ไขโดย Robin Barker) url ที่พร้อมใช้งานล่าสุดคือ: tips.webdesign10.com/files/rename.pl.txt
loretoparisi

1

เช่นเดียวกับสิ่งที่เคยแนะนำมานี่คือวิธีที่ฉันทำ:

find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;

ฉันตรวจสอบครั้งแรกกับ

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;

1

หนึ่งบรรทัดไม่มีลูป:

ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}

ตัวอย่าง:

$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
$ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt

+1 สำหรับการแสดงวิธีทุบตีเท่านั้นซึ่งไม่ได้ขึ้นอยู่กับการจับคู่ส่วนขยายที่มีอยู่ทั้งหมด ใช้ได้กับส่วนขยายอินพุตใด ๆ ไม่ว่าจะยาว 3 ตัวอักษรหรือ 4 ตัวอักษรยาวขึ้นไป
Ciprian Tomoiagă

0

น่าเสียดายที่การพกพาสะดวก คุณอาจต้องใช้เวทมนตร์ expr นิดหน่อย

for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done

ลบเสียงก้องเมื่อคุณมีความสุขมันทำในสิ่งที่คุณต้องการ

แก้ไข: basenameอาจจะอ่านได้มากกว่านี้เล็กน้อยสำหรับกรณีนี้แม้ว่าexprโดยทั่วไปจะมีความยืดหยุ่นมากกว่า


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

0

นี่คือสิ่งที่ฉันใช้ในการเปลี่ยนชื่อ.edgeไฟล์เป็น.blade.php

for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done

ทำงานเหมือนจับใจ


0

นอกจากนี้คุณยังสามารถสร้างฟังก์ชั่นใน Bash เพิ่มไปยัง.bashrcหรือบางสิ่งบางอย่างแล้วใช้งานได้ทุกที่ที่คุณต้องการ

change-ext() {
    for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
}

การใช้งาน:

change-ext css scss

แหล่งที่มาของรหัสในการทำงาน: https://stackoverflow.com/a/1224786/6732111


0

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

  1. สร้างเชลล์สคริปต์rename.shภายใต้ไดเรกทอรีปัจจุบันด้วยรหัสต่อไปนี้:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. ./rename.sh .old .newเรียกใช้งานโดย

    เช่น. ./rename.sh .html .txt

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