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


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.