rekurencyjnie dodaj rozszerzenie pliku do wszystkich plików

106

Mam kilka katalogów i podkatalogów zawierających pliki bez rozszerzenia. Chcę dodać .jpgdo wszystkich plików zawartych w tych katalogach. Widziałem skrypty bash do zmiany rozszerzenia pliku, ale nie tylko do dodania jednego. Musi też być rekurencyjna, czy ktoś może mi pomóc?

robjmills
źródło

Odpowiedzi:

228

Alternatywne polecenie bez jawnej pętli ( man find):

find . -type f -exec mv '{}' '{}'.jpg \;

Objaśnienie: to rekurencyjnie wyszukuje wszystkie pliki ( -type f), zaczynając od bieżącego katalogu ( .) i stosuje polecenie move ( mv) do każdego z nich. Zwróć również uwagę na cudzysłowy {}, aby nazwy plików ze spacjami (a nawet znakami nowej linii ...) były prawidłowo obsługiwane.

Stephan202
źródło
7
W szczególności ten działa lepiej, jeśli w strukturze katalogów jest ogromna liczba plików (powodując, że bash denerwuje się długością listy plików do iteracji).
DrAl,
@Al, jeśli odwołujesz się do forpętli denerwującej bash, aby iterować po liście plików, to nie jest poprawne. forPętla bash iteracyjnie wydaje każde mvpolecenie.
nik,
Pytanie: Czy findnajpierw tworzy listę plików przed wykonaniem -execinstrukcji? Chyba tak, ale chcę wyjaśnić ten punkt przed zakodowaniem nieskończonych pętli.
Boldewyn
2
to polecenie znajdzie również pliki z rozszerzeniem. Czy tego chce OP?
ghostdog74
1
@ ghostdog74: Ponieważ przyjął tę odpowiedź, powyższe najwyraźniej załatwiło sprawę. W przeciwnym razie, jak wspomniałeś poniżej, dodanie -not -name "*.*"wystarczy.
Stephan202,
62

to znajdzie pliki bez rozszerzenia i doda twój .jpg

find /path -type f -not -name "*.*" -exec mv "{}" "{}".jpg \;
ghostdog74
źródło
To z pewnością zapewni pożądany rezultat w 99% przypadków. +1
les
9

Trochę za późno, ale pomyślałem, że dodam, że lepszym rozwiązaniem (choć może mniej czytelnym) od dotychczasowych mogłoby być:

find /path -type f -not -name "*.*" -print0 | xargs -0 rename 's/(.)$/$1.jpg/'

Użycie find | xargswzorca generalnie skutkuje bardziej wydajnym wykonaniem, ponieważ nie trzeba rozwidlać nowego procesu dla każdego pliku.

Zauważ, że wymaga to wersji zmiany nazwy, którą można znaleźć w dystrybucjach o smaku Debiana (zwanej również prename), a nie tradycyjnej zmiany nazwy. Jest to jednak tylko mały skrypt w Perlu, więc byłoby dość łatwo użyć powyższego polecenia w dowolnym systemie.

Chad Huneycutt
źródło
4

lubię to,

for f in $(find . -type f); do mv $f ${f}.jpg; done

Nie spodziewam się, że będziesz mieć nazwy plików oddzielone spacjami.
Jeśli to zrobisz, nazwy będą musiały zostać nieco przetworzone.

Jeśli chcesz, aby wykonać polecenie z jakiegoś innego katalogu,
można wymienić find .z find /target/directory.

nik
źródło
1
Brakuje „do” i jeśli w nazwie pliku znajdują się spacje, lepiej będzie cytować nazwę pliku: for f in $ (find. -Type f); do mv "$ f" "$ {f} .jpg"; gotowe
DrAl
i prawdopodobnie uruchomiłbym to z katalogu najwyższego poziomu?
robjmills
@seengee: tak. Zwróć uwagę, że to polecenie pomija również myślnik -type.
Stephan202,
Musiałem gdzieś iść i pisać za szybko ... naprawianie teraz.
nik,
1

Aby zmienić nazwę wszystkich plików bez rozszerzenia w systemie Windows Basic, możesz to zrobić ren * *.jpg Ponieważ plik nie ma rozszerzenia, po prostu użyj *, lub jeśli chcesz zmienić png na jpg użyjren *.png *.jpg

Nuno
źródło
0

rename

nie jestem pewien, czy może zmienić nazwy plików bez rozszerzeń (jestem teraz w systemie Windows 7)

dfa
źródło
1
tak, ale zmieni również nazwy katalogów i nie ma sposobu, aby nakazać mu rekurencyjną pracę w podkatalogach (przynajmniej z wersją, którą mam na Ubuntu).
mirod
Znam co najmniej dwa różne polecenia o nazwie rename, jeden program w C zawarty w util-linux-ng i jeden program w Perlu (autorstwa samego Wall'a) na komputerach Debiana naszego uniwersytetu. W rzeczywistości żaden z nich nie wykonuje rekursji.
Boldewyn