Jak zmienić nazwę rozszerzenia dla kilku plików?

479

W katalogu mam kilka *.htmlplików. Chciałbym zmienić ich nazwy na wszystkie*.txt

Jak mogę to zrobić? Używam powłoki bash.

bmw0128
źródło

Odpowiedzi:

382

Aby uzyskać lepsze rozwiązanie (tylko z funkcją bash, w przeciwieństwie do połączeń zewnętrznych), zobacz jedną z pozostałych odpowiedzi .


Następujące czynności zrobiłyby i nie wymagają, aby system miał renameprogram (chociaż najczęściej miałbyś to w systemie):

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

EDYCJA: Jak wskazano w komentarzach, nie działa to dla nazw plików ze spacjami bez odpowiedniego cytowania (teraz dodanego powyżej). W przypadku pracy wyłącznie na własnych plikach, o których wiesz, że w nazwach plików nie ma spacji, będzie to działać, ale ilekroć napiszesz coś, co może być ponownie wykorzystane później, nie pomijaj właściwego cytowania.

Mikael Auno
źródło
47
Alternatywa, bez basename i z cudzysłowami: mv "$ {file}" "$ {file /%. Html / .txt}" (szczegóły w bash man, rozszerzenie parametrów)
Rodrigo Queiro
7
Oczywiście dobrze, jeśli wszystkie pliki znajdują się w bieżącym katalogu, ponieważ basename usuwa część nazwy ścieżki. Tylko uważaj!
Jonathan Leffler,
6
To rozwiązanie jest złe, nie tylko dlatego, że jest powolne, ale także dlatego, że nie działa z nazwami plików ze spacjami. ZAWSZE powinieneś robić odpowiednie cytaty w skryptach bash. mv „$ file” „$ (basename„ $ file ”.html)”. txt byłby znacznie lepszy. Ale nadal mv „$ files” „$ {files% .html} .txt” jest znacznie lepszy.
Balázs Pozsár
8
w oknach, które po prostu robiszren *.a *.b
Muhammad Umer
2
Używaj przynajmniej podanej POSIX $()zamiast starszej składni backtick. Poprawia czytelność i sprawia, że ​​składnia jest znacznie mniej dwuznaczna, gdy masz znaki, które musiałyby być poprzedzone odwrotnym ukośnikiem, aby były dosłowne wewnątrz podstawienia polecenia tym ostatnim.
Charles Duffy,
668

Jeśli używasz bash, nie potrzebujesz zewnętrznych poleceń, takich jak sed, basename, zmiana nazwy, wyrażenie itp.

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done
ghostdog74
źródło
12
A jeśli nie znasz rozszerzenia pliku, którego możesz użyć "${file%.*}.txt", może to być niebezpieczne dla plików bez rozszerzenia.
Jess,
1
Uwaga dla każdego, kto ma problem z działaniem tak, jak ja: zwróć uwagę, że $w nawiasach klamrowych nie ma nic !
doug65536
5
Potrzebuję sposobu, aby na stałe
ulubić
7
@danip Konstrukcja znaku procentowego w nawiasie odcina znaki od końca. Istnieje również konstrukcja hash-nawias klamrowy, która usuwa znaki z początku. Sprawdź to: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
4
Inna odpowiedź dotycząca wymiany stosu (której nie mogę znaleźć!) Sugeruje to, ale także za pomocą --„operatora”: mv - „$ plik” „$ {plik% .html} .txt” Ten operator zapobiega nazwom plików rozpoczynającym się od a - - z parsowania przez mv jako argumentów.
rcreswick,
191
rename 's/\.html$/\.txt/' *.html

robi dokładnie to, co chcesz.

Bursztyn
źródło
Nie sądzę, że możesz użyć dosłownego wyrażenia regularnego w bashu, jak sugerujesz - jakiej powłoki używasz?
DaveR
1
używam terminala Mac
bmw0128
Oto strona podręcznika man dla wersji zmiany nazwy na Ubuntu: unixhelp.ed.ac.uk/CGI/man-cgi?rename
Amber
rename to polecenie w niektórych systemach. Mam skrypt Perla (pierwotnie z pierwszej książki o wielbłądach), który spełnia swoje zadanie. Istnieje również program GNU o tej samej nazwie, który wykonuje mniej więcej tę samą pracę. Mój komputer Mac nie ma systemowej komendy „zmień nazwę” - lub nie ma jej ŚCIEŻKI (która jest umiarkowanie wyczerpująca).
Jonathan Leffler,
Istnieje formuła zmiany nazwy w Homebrew.
revprez
112

To działało dla mnie w OSX od .txt do .txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
Steven Lizarazo
źródło
4
Działa dobrze również w systemie Linux.
Diziet
To oprócz punktu, ale iść z .txtaby .txt_bakpo prostu mieć do łączenia _bak;)
corwin.amber
3
Jest to przydatne przy rekursywnej zmianie nazwy
leachryanb
Świetny! (pod Ubuntu 16.04) Mój praktyczny przypadek użycia, zmiana nazwy .scssna .sass(po konwersji w miejscu…):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Frank Nocke
2
działało to z plikami +6000, zmiana nazwy zgłosiła „lista argumentów była za długa”
Tony Cronin
94

Chcesz użyć rename:

rename -S .html .txt *.html

To robi dokładnie to, co chcesz - zmieni to rozszerzenie z .htmlna .txtdla wszystkich pasujących plików *.html.

Uwaga: Greg Hewgill poprawnie wskazuje, że nie jest to wbudowane bash; i jest osobnym poleceniem Linuksa. Jeśli potrzebujesz czegoś w systemie Linux, powinno to działać poprawnie; jeśli potrzebujesz czegoś więcej na różnych platformach, spójrz na jedną z pozostałych odpowiedzi.

DaveR
źródło
7
Chociaż jest to dobre rozwiązanie, renameprogram nie jest powiązany bashi nie jest dostępny na wszystkich platformach. Widziałem to tylko w systemie Linux.
Greg Hewgill
15
„$ rename .html .txt * .html” powoduje… błąd składni w (eval 1) linii 1, w pobliżu „.”
Amber
8
Poprawna składnia jest rename -S .html .text *.htmlgdzie -Soznacza--subst-all
Marek Sebera
8
zmiana nazwy instalacji parzenia
Nick
4
Zmiana nazwy @GregHewgill jest dostępna dla systemu Mac OS z HomeBrew
CodeBrauer
36

Na komputerze Mac ...

  1. Zainstaluj zmień nazwę, jeśli nie masz:brew install rename
  2. rename -S .html .txt *.html
izilotti
źródło
15

Dla użytkowników Ubuntu:

rename 's/\.html$/\.txt/' *.html
Bheru Lal Lohar
źródło
To nie jest rekurencyjne, ale działało dla mnie na Ubuntu 14.04.
Max Wallace
9

To najsprytniejsze rozwiązanie, jakie znalazłem, które działa na OSX i Linuksie, i działa również ładnie z git!

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

i z git:

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

bdombro
źródło
8

Oto przykład polecenia zmiany nazwy:

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

-N oznacza, że ​​jest to uruchomienie testowe i tak naprawdę nie zmieni żadnych plików. Wyświetli ci listę plików, których nazwy można zmienić, jeśli usuniesz -n. W powyższym przypadku skonwertuje wszystkie pliki w bieżącym katalogu z rozszerzenia .htm na .html.

Jeśli wynik powyższego uruchomienia testowego wyglądał dobrze, możesz uruchomić ostateczną wersję:

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

Opcja -v jest opcjonalna, ale warto ją uwzględnić, ponieważ jest to jedyny rekord, w którym będziesz mieć zmiany dokonane za pomocą polecenia rename, jak pokazano w przykładowym wyniku poniżej:

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

Trudna część pośrodku to podstawienie Perla wyrażeniami regularnymi, podkreślone poniżej:

rename -v s/\.htm$/\.html/’ *.htm
AA
źródło
6

To pytanie wyraźnie wspomina o Bash, ale jeśli zdarzy ci się mieć ZSH, jest to dość proste:

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

Jeśli otrzymasz, zsh: command not found: zmvpo prostu uruchom:

autoload -U zmv

A potem spróbuj ponownie.

Dzięki temu oryginalnemu artykułowi na wskazówkę o zmv.

Michael Leonard
źródło
4

Po zaindeksowaniu czyjejś witryny internetowej skończyło się to tym, że tysiące plików nie ma rozszerzenia .html w szerokim drzewie podkatalogów.

Aby zmienić nazwę wszystkich w jednym ujęciu, z wyjątkiem plików, które mają już rozszerzenie .html (większość z nich w ogóle nie miała), działało to dla mnie:

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

W przypadku OP mogę to nieco zmodyfikować, aby zmienić tylko nazwy plików * .txt, tak jak poniżej:

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

W podziale (hammertime!):

-iname * .txt
- oznacza, że ​​uwzględniają TYLKO pliki, które kończą się na .txt

mv -iv "{}. {txt, html}" - Gdy find podaje {} jako nazwę pliku, $ {nazwa_pliku%. *} wyodrębnia swoją nazwę basename bez żadnego rozszerzenia, aby utworzyć parametry dla mv . bash bierze {txt, html}, aby przepisać go jako dwa parametry, więc końcowe polecenie działa jako:mv -iv "filename.txt" "filename.html"

Niezbędna poprawka: radzenie sobie ze spacjami w nazwach plików

Marcos
źródło
4

Poleceniammv wydaje się bardzo sprawnie wykonać to zadanie na ogromną liczbę plików (dziesiątki tysięcy na sekundę). Na przykład, aby zmienić nazwę wszystkich .xmlplików na .htmlpliki, użyj tego:

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

;będzie pasował do ścieżki, *będzie pasował do nazwy pliku, a te są nazywane #1i #2w nazwie zastępczej.

Odpowiedzi na podstawie execlub potoki były zbyt wolne lub nie powiodły się w przypadku bardzo dużej liczby plików.

Roko Mijic
źródło
3

Spróbuj tego

rename .html .txt *.html 

stosowanie:

rename [find] [replace_with] [criteria]
P Sreedhar
źródło
3

Trochę późno na imprezę. Możesz to zrobić za pomocą xargs:

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

Lub jeśli wszystkie twoje pliki są w jakimś folderze

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}
esp
źródło
3
Nie. Nie analizujls . To polecenie jest niedorzeczne: bezużytecznie używa globu z lszamiast globalnego użycia globusa. Spowoduje to zerwanie nazw plików zawierających spacje, cytaty i (z powodu braku cytatów) znaków globalnych.
gniourf_gniourf
Do Twojej wiadomości, link do tego artykułu zawiera zaktualizowaną notatkę, która mówi, że nowsze LS „poprawnie” shell ucieka ”pliki, jeśli zostaną wydrukowane na terminalu.” Twój punkt jest jednak nadal dobrą zasadą.
Katastic Voyage
3

To dobry sposób na modyfikację wielu rozszerzeń jednocześnie:

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

Uwaga: uważaj, aby rozmiar rozszerzenia był taki sam (???)

Nick De Greek
źródło
2

Ładne i proste!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
Deano
źródło
2

Jeśli wolisz PERL, istnieje krótki skrypt PERL (pierwotnie napisany przez Larry'ego Walla, twórcę PERL), który zrobi dokładnie to, co chcesz tutaj: tips.webdesign10.com/files/rename.pl.txt .

W twoim przykładzie należy wykonać następujące czynności:

rename.pl 's/html/txt/' *.html
dudusan
źródło
2
To pytanie zostało już dawno udzielone i zaakceptowane i nie wydaje się, aby twoja odpowiedź przyniosła coś więcej niż to, co zostało już powiedziane.
ChristopheLec
1
+1, ponieważ był to skrypt Larry'ego Walla (zmodyfikowany przez Robina Barkera). Ostatni dostępny adres URL to: tips.webdesign10.com/files/rename.pl.txt
loretoparisi
1

Podobnie jak wcześniej zasugerowano, tak to zrobiłem:

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

Najpierw zatwierdziłem

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;
Carl Bosch
źródło
1

Jedna linia, bez pętli:

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

Przykład:

$ 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
Christian Bongiorno
źródło
+1 za pokazanie tylko trybu bash, który nie zależy od dokładnego dopasowania istniejącego rozszerzenia. Działa to z każdym rozszerzeniem wejściowym, bez względu na to, czy jest to 3 znaki, 4 znaki lub więcej
Ciprian Tomoiagă
0

Niestety nie jest to łatwe do przenoszenia. Prawdopodobnie potrzebujesz odrobiny magii expr.

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

Usuń echo, gdy będziesz zadowolony, że zrobi to, co chcesz.

Edycja: basename jest prawdopodobnie nieco bardziej czytelna w tym konkretnym przypadku, chociaż exprogólnie jest bardziej elastyczna.

CB Bailey
źródło
Chociaż może nie być to najlepsza odpowiedź na pytanie, to była dla mnie! Potrzebowałem sposobu, aby zmienić nazwę tylko w łańcuchu całej ścieżki, a nie tylko nazwy pliku. Dzięki za opublikowanie!
pączek
0

Oto, do czego zmieniałem nazwy .edgeplików.blade.php

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

Działa jak urok.

Nixon Kosgei
źródło
0

Możesz także utworzyć funkcję w Bash, dodać ją .bashrclub coś, a następnie użyć jej w dowolnym miejscu.

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

Stosowanie:

change-ext css scss

Źródło kodu w funkcji: https://stackoverflow.com/a/1224786/6732111

J Kluseczka
źródło
0

Zmień nazwy rozszerzeń plików dla wszystkich plików w bieżącym katalogu i podkatalogach bez żadnych innych pakietów (użyj tylko skryptu powłoki):

  1. Utwórz skrypt powłoki rename.shw bieżącym katalogu z następującym kodem:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. Uruchom to ./rename.sh .old .new.

    Na przykład. ./rename.sh .html .txt

Neo Liu
źródło