Odpowiedzi:
Przenośny sposób (który działa na każdym systemie zgodnym z POSIX):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
W bash4 możesz użyć globstar, aby uzyskać rekurencyjne globusy (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Komenda (perl) renamew Ubuntu może zmieniać nazwy plików przy użyciu składni wyrażeń regularnych perl, którą można łączyć z globstar lub find:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
Zobacz także http://mywiki.wooledge.org/BashFAQ/030
${1%.abc}...
sh -c pierwszym argumentem przypisuje się $ 0, a wszelkie pozostałe argumenty są przypisywane do parametrów pozycyjnych . Więc _jest obojętne argumentem, a „{}” jest pierwszym argumentem pozycyjnym sh -c.
Wykona to wymagane zadanie, jeśli wszystkie pliki znajdują się w tym samym folderze
rename 's/.abc$/.edefg/' *.abc
Aby zmienić nazwę plików rekurencyjnie, użyj tego:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcw nowoczesnej wersji Bash.
sna początku i jakie inne opcje mogę tam wykorzystać. Dzięki !
Jednym z problemów z rekurencyjnymi nazwami jest to, że bez względu na metodę, której używasz do zlokalizowania plików, przekazuje całą ścieżkę rename, a nie tylko nazwę pliku. Utrudnia to skomplikowane zmiany nazw w zagnieżdżonych folderach.
Używam find„s -execdirdziałania, aby rozwiązać ten problem. Jeśli użyjesz -execdirzamiast -exec, określone polecenie jest uruchamiane z podkatalogu zawierającego dopasowany plik. Zamiast przejść całą ścieżkę rename, przechodzi ona tylko ./filename. To znacznie ułatwia napisanie wyrażenia regularnego.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
Szczegółowo:
-type f oznacza tylko wyszukiwanie plików, a nie katalogów-name '*.abc' oznacza tylko pasujące nazwy plików, które kończą się na .abc'{}'to symbol zastępczy, który oznacza miejsce, w którym -execdirwstawi znalezioną ścieżkę. Pojedyncze cudzysłowy są wymagane, aby umożliwić obsługę nazw plików ze spacjami i znakami powłoki.-typei -namesą znakiem kontynuacji linii bash. Używam ich, aby ten przykład był bardziej czytelny, ale nie są one potrzebne, jeśli umieścisz wszystkie polecenia w jednym wierszu.-execdirWymagany jest jednak odwrotny ukośnik na końcu linii. Jest tam, aby uciec od średnika, który kończy uruchamiane polecenie -execdir. Zabawa!Objaśnienie wyrażenia regularnego:
s/ początek wyrażenia regularnego\.\/dopasuj wiodące ./, które przechodzi -execdir. Użyj \, aby wyjść z. i / metaznaki (uwaga: ta część różni się w zależności od wersji find. Zobacz komentarz od użytkownika @apollo)(.+)dopasuj nazwę pliku. Nawiasy przechwytują dopasowanie do późniejszego wykorzystania\.abc ucieczka kropka, dopasuj abc$ zakotwicz dopasowanie na końcu łańcucha
/ oznacza koniec części „dopasowującej” wyrażenia regularnego i początek części „zamień”
version1_ dodaj ten tekst do każdej nazwy pliku
$1odwołuje się do istniejącej nazwy pliku, ponieważ przechwyciliśmy ją w nawiasach. Jeśli używasz wielu zestawów nawiasów w części „Dopasuj”, możesz odwołać się do nich tutaj, używając 2 USD, 3 USD itp..abcnowa nazwa pliku zakończy się na .abc. W sekcji „zamień” nie ma potrzeby ucieczki od metaznaku kropkowego/ koniec wyrażenia regularnegoPrzed
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Po
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Wskazówka: renameOpcja -n jest przydatna. Robi próbę na sucho i pokazuje, jakie nazwy zmieni, ale nie wprowadza żadnych zmian.
--execdirnie przeszedł on na początek, ./więc \.\/część wyrażenia regularnego można pominąć. Może dlatego, że korzystam z OSX, a nie Ubuntu
Inny przenośny sposób:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Zobacz także wpis, dlaczego nie powinieneś analizować ls.
Edycja: jeśli musisz użyć basename, składnia wyglądałaby następująco:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
To właśnie zrobiłem i działałem tak, jak chciałem. Użyłem mvpolecenia. Miałem wiele .3gpplików i chciałem zmienić ich nazwy na wszystkie.mp4
Oto krótki oneliner:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Który po prostu skanuje bieżący katalog, pobiera wszystkie pliki .3gp, a następnie zmienia nazwy (przy użyciu mv) na ren-name_of_file.mp4
file.3gpna file.3gp.mp4, co może nie być tym, czego chce większość ludzi.
.3gplub .mp4tutaj były tylko w celach ilustracyjnych.
basename "$i" .mp4poprzedniego rozszerzenia zamiast „ren- $ i.mp4”.
Chciałbym użyć polecenia MMV z pakietu o tej samej nazwie :
mmv ';*.abc' '#1#2.edefg'
W ;dopasowuje zero lub więcej */i odpowiada #1na wymianę. Do *odpowiada #2. Byłaby to wersja nierekurencyjna
mmv '*.abc' '#1.edefg'
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: Dlaczego użycie akcji „-execdir” nie jest bezpieczne dla katalogu znajdującego się w zmiennej PATH?
-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: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
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.