Rekurencyjnie zmieniaj nazwy plików (zmień rozszerzenie) w systemie Linux

22

Jak zmienić nazwę wszystkich plików w katalogu, rekurencyjnie, zmieniając jedno rozszerzenie pliku na inne, dla tysięcy plików w tysiącach podfolderów? Widzę wiele poleceń, które robią prawie to, czego chcę, ale niezupełnie.

find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."

...

rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile
endolit
źródło
1
Czy masz Debian renamelub Red Hat rename?
Ignacio Vazquez-Abrams,
@Ignacio: Ubuntu = Debian?
endolith,
Tak, Ubuntu jest pochodną Debiana.
Ignacio Vazquez-Abrams,

Odpowiedzi:

23

Domyśliłam się

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile

oczywiście usuń -v podczas robienia tego, inaczej zmarnuje czas na wyświetlanie wszystkich plików

endolit
źródło
14

Coś jak:

find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
Cyrus
źródło
ten działał dla mnie najlepiej
cwd
14

Z zsh:

autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'

Usuń, -naby faktycznie zmienić nazwę.

Gilles „SO- przestań być zły”
źródło
1
Fantastyczna odpowiedź!
Chris Knadler
4

Odkryłem, że ta metoda jest łatwiejsza do odczytania:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/"

Przynajmniej w przypadku pochodnych Ubuntu zmiana nazwy pobiera listę plików ze STDIN, jeśli nie ma ich w wierszu poleceń. Można to łatwo przetestować za pomocą:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"

dopóki nie zrobisz tego dobrze.

Bernd Wechner
źródło
1

Zmień nazwy plików i katalogów za pomocą find -execdir | rename

Jeśli zamierzasz zmienić nazwę zarówno plików, jak i katalogów, nie tylko za pomocą przyrostka, to jest to dobry wzorzec:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

Niesamowita -execdiropcja robi cdw katalogu a przed wykonaniem renamepolecenia, w przeciwieństwie do -exec.

-depth upewnij się, że zmiana nazwy nastąpi najpierw dla dzieci, a następnie dla rodziców, aby zapobiec potencjalnym problemom z brakującymi katalogami rodziców.

-execdir jest wymagane, ponieważ zmiana nazwy nie działa dobrze w przypadku ścieżek wejściowych innych niż basename, np. nie działa:

rename 's/findme/replaceme/g' acc/acc

PATHHacking jest wymagane, ponieważ -execdirma jeden bardzo przykry wadę: findjest bardzo uparty i nie chce nic robić ze -execdirjeśli masz żadnych ścieżek względnych w PATHzmiennej środowiskowej, na przykład ./node_modules/.bin, w przypadku braku z:

find: ścieżka względna „./node_modules/.bin” jest zawarta w zmiennej środowiskowej PATH, która nie jest bezpieczna w połączeniu z działaniem -execdir funkcji find. Usuń ten wpis z $ PATH

Zobacz także: /ubuntu/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdirto rozszerzenie GNU do POSIX . renamejest oparty na Perlu i pochodzi z renamepakietu. Testowane w Ubuntu 18.10.

Zmień nazwę obejścia obejścia

Jeśli twoje ścieżki wejściowe nie pochodzą findlub jeśli masz dość relatywnej irytacji ścieżki, możemy użyć Perla lookahead, aby bezpiecznie zmienić nazwy katalogów jak w:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Nie znalazłem dogodnym dla analogowych -execdirz xargs: xargs: Zmiana katalogu roboczego do ścieżki pliku przed wykonaniem?

Jest sort -rto konieczne, aby upewnić się, że pliki następują po odpowiednich katalogach, ponieważ dłuższe ścieżki pojawiają się po krótszych z tym samym prefiksem.

Ciro Santilli
źródło