Zmień nazwę wielu plików za pomocą mv, aby zmienić rozszerzenie


27

Chcę zmienić nazwę plików, aby zmienić ich rozszerzenie, skutecznie starając się to osiągnąć

mv *.txt *.tsv

Ale robiąc to, otrzymuję:

* .tsv nie jest katalogiem

Wydaje mi się nieco dziwne, że pierwsze 10 hitów Google mvpowinno tak działać.


Powinieneś wyjaśnić, jak dokładnie zmienić nazwę tych plików.
Totor

1
Cóż, mam pliki z rozszerzeniem * .gappedPeak i chcę zmienić ich nazwę na * .bed. wszystkie znajdują się w tym samym katalogu, powinno to być bardzo proste, ale aby odnieść sukces, potrzebowałem pełnej pętli for
Sander Van der Zeeuw

Myślę, że to, co znalazłeś w Google, dotyczy MSDOS.
tiktak

Alternatywne rozwiązanie @devnull jest naprawdę pomocne
lucasvw,

Odpowiedzi:


22

Po wydaniu polecenia:

mv *.txt *.tsv

powłoka, załóżmy bash, rozwija symbole wieloznaczne, jeśli są jakieś pasujące pliki (w tym katalogi). Lista plików jest przekazywana do programu tutaj mv. Jeśli nie zostaną znalezione żadne dopasowania, wersja nierozwinięta jest przekazywana.

Znowu: powłoka rozszerza wzorce, a nie program.


Mnóstwo przykładów jest chyba najlepszym sposobem, więc zaczynamy:

Przykład 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Teraz w mvlinii dzieje się, że powłoka rozwija *.txtsię do pasujących plików. Ponieważ nie ma *.tsvplików, które nie zostaną zmienione.

mvPolecenie nazywa się z dwóch specjalnych argumentów :

  • argc: Liczba argumentów, w tym program.
  • argv: Tablica argumentów, w tym program jako pierwszy wpis.

W powyższym przykładzie byłoby to:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

mvKontrola programu, aby zobaczyć czy ostatni argument *.tsvjest katalogiem. Ponieważ tak nie jest, program nie może kontynuować pracy, ponieważ nie jest przeznaczony do łączenia plików. (Zazwyczaj przenieś wszystkie pliki do jednego.) Nie twórz katalogów według kaprysu.

W rezultacie przerywa działanie i zgłasza błąd:

mv: target ‘*.tsv’ is not a directory

Przykład 2:

Teraz, jeśli zamiast tego powiesz:

$ mv *1.txt *.tsv

mvPolecenie jest wykonywane z:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

Teraz ponownie mvsprawdź, czy *.tsvistnieje. W przeciwnym razie plik file1.txtzostanie przeniesiony do *.tsv. To znaczy: nazwa pliku zmienia się *.tsvna gwiazdkę i wszystko.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Przykład 3:

Jeśli zamiast tego powiedziałeś:

$ mkdir *.tsv
$ mv *.txt *.tsv

mvPolecenie jest wykonywane z:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

Ponieważ *.tsvteraz jest katalog, pliki są tam przenoszone.


Teraz: używając poleceń, takich jak some_command *.tsvkiedy rzeczywiście chcesz zachować symbol wieloznaczny, zawsze powinieneś go zacytować. Cytując, zapobiegasz rozszerzaniu symboli wieloznacznych, jeśli powinny być jakieś dopasowania. Powiedz np mkdir "*.tsv".

Przykład 4:

Rozszerzenie można wyświetlić jeszcze, jeśli wykonasz na przykład:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Przykład 5:

Teraz: mvpolecenie może i działa na wielu plikach. Ale jeśli jest ich więcej niż dwa, ostatni musi być katalogiem docelowym. (Opcjonalnie możesz użyć tej -t TARGET_DIRopcji, przynajmniej dla GNU mv.)

Więc to jest OK:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Tutaj mvbędzie się nazywać z:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

i wszystkie pliki trafiają do katalogu foo.


Co do twoich linków. Podałeś jeden (w komentarzu), w którym mvwcale nie wspomniano, ale rename. Jeśli masz więcej linków, które możesz udostępnić. Podobnie jak w przypadku stron podręcznika, w których twierdzisz, że jest to wyrażone.


30

Wiem, że to nie odpowiada na twoje pytanie, ale jeśli szukałeś innego sposobu zmiany nazwy plików w porównaniu do pętli obejścia, dlaczego nie użyć find? Używałem tego polecenia wiele razy, aby zastąpić rozszerzenia plików w dużych katalogach setkami tysięcy plików. Powinno to działać na każdym systemie zgodnym z POSIX:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Podział poleceń:

  1. ' .' => ścieżka wyszukiwania zaczynająca się od bieżącego katalogu oznaczonego przez '. „

  2. -name=> ustaw szukaną nazwę dopasowania (w tym przypadku wszystkie pliki, które kończą się .gappedPeak)

  3. -exec => wykonaj następujące polecenie przy każdym dopasowaniu

  4. sh -c => 'exec' tworzy niezależne środowisko powłoki dla każdego dopasowania

  5. mv "$1" "${1%.gappedPeak}.bed"=> mvpierwsza zmienna (oznaczona przez $ 1 ), która jest bieżącą nazwą pliku, do nowej nazwy. Tutaj wykonuję dopasowanie podciągu i usuwam; więc weź najpierw var, $ 1 i użyj, %aby usunąć .gappedPeakz ciągu. .bedNa końcu po prostu skleja pozostałą zmienną, która jest teraz po prostu , z , tworząc nową nazwę pliku.test#.bedtest#.bed

  6. Podkreślenie jest symbolem zastępczym dla 0 USD

  7. {}Otrzymuje każdego ( *.gappedPeak) pliku znalezionego przez findpolecenia i staje $ 1 do shkomendy.

  8. \;oznacza koniec -execpolecenia. Możesz także użyć ';'lub ";".

Przykład:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed

Czy mógłbyś wykonać polecenie opisujące, co robi każda część?
user1717828,

Przepraszam za to, zaktualizowałem swój post. Mam nadzieję, że to pomaga.
devnull

1
Wielkie dzieki! Dzięki przewodnikowi bash i twojemu wyjaśnieniu udało mi się zdobyć wszystko.
user1717828,

Nie ma problemu. Cieszę się, że to pomaga.
devnull

Działa jak marzenie. Oto kolejny uproszczony przykład file.abc-> blub.xyzw wielu katalogach podrzędnych:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn

9

mv *.txt *.tsvnie działa; mvmoże zmienić nazwę tylko jednego pliku na raz. Albo źle zrozumiałeś wyjaśnienia, albo są w błędzie.

mmvi renamemoże zmieniać nazwy kilku plików jednocześnie. Ale istnieją dwie wersje, renamektóre są nazywane inaczej. Tutaj powinno być wiele pytań.


1
cyberciti.biz/tips/… Pierwszy hit w Google mówi, że mv powinien również działać, dlatego uważam, że to takie dziwne
Sander Van der Zeeuw

3
@SanderVanderZeeuw Nie wiem, co tam czytasz. Przykłady wykorzystują rename, a nie mv.
Hauke ​​Laging

1
przepraszam, że wkleiłem niewłaściwy kod HTML. To był jeden udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw

3
@SanderVanderZeeuw Żenujące. Te osoby oferują kursy? Niestety nie widzę tam możliwości kontaktu. Możesz łatwo sprawdzić, czy to działa. Ale w mv *.txt *.tsv mvnie (zwykle) nie widzi *.txtlub wyświetla *.tsvnazwy plików z rozszerzeniem powłoki. Liczba plików rozwijanych przez te symbole wieloznaczne byłaby „losowa”. Jedyną sytuacją, w której to działa, jest plik o nazwie, *.txtktórego nazwa zostanie zmieniona na (dosłownie) *.tsv(bez cytowania bashopcji nullglobnie można ustawić).
Hauke ​​Laging

1
Albo gorzej. Jeśli ktoś ma jeden plik o nazwie np foo.txti jedną o nazwie będzie zastąpić istniejący plik ...baz.tsvmv *.txt *.tsv.tsv
Runium

4

Na przykład, jeśli masz asd.txti qwe.txtpliki w katalogu po uruchomieniu polecenia mv *.txt *.tsv, próbuje przenieść te dwa pliki do katalogu o nazwie *.tsv. Ponieważ nie ma takiego katalogu, pojawia się błąd.


Dzięki, to częściowo wyjaśnia. Wciąż wydaje mi się dziwne, że widzę tak wiele stron podręcznika, na których twierdzą, że mv powinno działać na wielu.
Sander Van der Zeeuw

2

rename(1)

renamejest skryptem perla autorstwa Larry'ego Walla, twórcy perla. Wymaga wyrażenia regularnego Perla i działa na nazwie pliku.

rename 's/\.txt$/.tsv/' *.txt

Instalacja

Debian / Ubuntu

Jeśli musisz zainstalować renamena Debian / Ubuntu, możesz to zrobić

sudo apt install rename

0

Inną opcją do rozważenia jest użycie:

cp -p *.txt *.tsv
rm -f *.txt
  • Pierwszy wiersz kopiuje wszystkie *.txtpliki *.tsv, zachowując ich atrybuty za pomocą -pflagi.
  • Drugi wiersz usuwa wszystkie pliki ze wzorem *.txt
  • Ta metoda wymaga wystarczającej ilości miejsca na dysku do tymczasowego przechowywania zarówno plików źródłowych, jak i docelowych
  • Ta metoda jest wolniejsza niż ta, mvktóra po prostu zmienia katalog / nazwę pliku bez przenoszenia plików, chyba że znajdują się na innej partycji.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.