it-swarm.dev

Jak mohu změnit příponu více souborů rekurzivně z příkazového řádku?

Mám mnoho souborů s .abc rozšíření a chcete je změnit na .edefg
Jak to provést z příkazového řádku?

Mám kořenovou složku s mnoha podsložky, takže řešení by mělo fungovat rekurzivně.

75
tommyk

Přenosný způsob (který bude fungovat na jakémkoli systému kompatibilním s POSIX):

find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;

V bash4 můžete pomocí globstar získat rekurzivní glóby (**):

shopt -s globstar
for file in /the/path/**/*.abc; do
  mv "$file" "${file%.abc}.edefg"
done

Příkaz (Perl) rename v Ubuntu může přejmenovat soubory pomocí syntaxe regulárního výrazu Perl, kterou můžete kombinovat s globstar nebo 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/' {} +

Viz také http://mywiki.wooledge.org/BashFAQ/0

89
geirha

To provede požadovaný úkol, pokud jsou všechny soubory ve stejné složce

rename 's/.abc$/.edefg/' *.abc

Chcete-li přejmenovat soubory rekurzivně, použijte toto:

find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
49
Chakra

Jedním z problémů s rekurzivními jmény je to, že ať už použijete jakoukoli metodu k nalezení souborů, předá celou cestu rename, nejen název souboru. To ztěžuje složité přejmenování vnořených složek.

Používám find 's -execdir akce k vyřešení tohoto problému. Pokud používáte -execdir namísto -exec, zadaný příkaz je spuštěn z podadresáře obsahujícího odpovídající soubor. Takže namísto předání celé cesty k rename to pouze projde ./filename. Díky tomu je psaní regexu mnohem snazší.

find /the/path -type f \
               -name '*.abc' \
               -execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;

Podrobně:

  • -type f znamená pouze hledat soubory, nikoli adresáře
  • -name '*.abc' znamená pouze shodovat názvy souborů končící na .abc
  • '{}' je zástupný symbol, který označuje místo, kde -execdir vloží nalezenou cestu. Jednotlivé uvozovky jsou povinné, aby bylo možné zpracovat názvy souborů s mezerami a znaky Shell.
  • Zpětná lomítka za -type a -name jsou znak pro pokračování v bashovém řádku. Používám je, aby byl tento příklad čitelnější, ale nejsou potřeba, pokud umístíte celý příkaz na jeden řádek.
  • Zpětné lomítko na konci -execdir řádek je vyžadován. Je zde, aby unikl středník, který ukončí příkaz spuštěný -execdir. Zábava!

Vysvětlení regexu:

  • s/ začátek regexu
  • \.\/ odpovídá úvodnímu ./, který -execdir projde. Pomocí\unikněte. a/metacharacters (poznámka: tato část se liší v závislosti na verzi find. Viz komentář od uživatele @apollo)
  • (.+) odpovídá názvu souboru. Závorky zachycují shodu pro pozdější použití
  • \.abc unikni tečce, shoduj se s abc
  • $ ukotvit zápas na konci řetězce

  • / označuje konec „shodné“ části regexu a začátek části „nahradit“

  • version1_ přidejte tento text ke každému názvu souboru

  • $1 odkazuje na existující název souboru, protože jsme jej zachytili závorkami. Pokud používáte více sad závorek v části „match“, můžete na ně odkazovat zde pomocí $ 2, $ 3 atd.
  • .abc nový název souboru skončí na .abc. V části „nahradit“ není třeba unikat tečkovým metacharakterům
  • / konec regexu

Před

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

Tip: Užitečná je volba rename. Provádí suchý běh a ukazuje, jaká jména se změní, ale neprovádí žádné změny.

14
Christian Long

Další přenosný způsob:

find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
5
aNeutrino
# Rename all *.txt to *.text
for f in *.txt; do 
mv -- "$f" "${f%.txt}.text"
done

Viz také položka o tom, proč byste neměli analyzovat ls.

Edit: pokud musíte použít basename, vaše syntaxe bude:

for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done

https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files

3
ashanrupasinghe

Použil bych příkaz mmv z balíček se stejným názvem :

mmv ';*.abc' '#1#2.edefg'

The ; odpovídá nule nebo více */ a odpovídá #1 v nahrazení. The * odpovídá #2. Nerekurzivní verze by byla

mmv '*.abc' '#1.edefg'
1
MvG

Našel jsem snadný způsob, jak toho dosáhnout. Chcete-li změnit příponu mnoha souborů z jpg na pdf, použijte:

for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
0
Peaceful

To je to, co jsem udělal a pracoval docela přesně tak, jak jsem chtěl. Použil jsem příkaz mv. Měl jsem více .3gp soubory a já jsem je chtěl všechny přejmenovat na .mp4

Zde je krátká nabídka:

for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done

Což jednoduše prohledá aktuální adresář, vyzvedne všechny soubory .3gp a přejmenuje (pomocí mv) na ren-name_of_file.mp4

0
KhoPhi

Přejmenujte soubory a adresáře pomocí find -execdir | rename

Pokud chcete přejmenovat soubory i adresáře nejen pomocí přípony, je to dobrý vzor:

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

Úžasná volba -execdir Provede do adresáře cd před provedením příkazu rename, na rozdíl od -exec.

-depth Zajistěte, aby k přejmenování došlo nejprve u dětí a poté u rodičů, abyste předešli potenciálním problémům s chybějícími nadřazenými adresáři.

-execdir Je vyžadováno, protože přejmenování se nepracuje dobře se vstupními cestami bez názvu jména, např. následující selže:

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

Hackování PATH je vyžadováno, protože -execdir Má jednu velmi nepříjemnou nevýhodu: find je velmi nadšený a odmítá cokoli dělat s -execdir, Pokud máte nějaké relativní cesty ve vaší proměnné prostředí PATH, např ./node_modules/.bin, Selhání s:

find: Relativní cesta „./node_modules/.bin“ “je zahrnuta v proměnné prostředí PATH, což je nezabezpečené v kombinaci s -execdirovou akcí find. Odstraňte tuto položku z $ PATH

Viz také: Proč použití akce '-execdir' není bezpečné pro adresář, který je v PATH?

-execdir Je GNU find rozšíření POSIX . rename je založeno na Perlu a pochází z balíčku rename Testováno v Ubuntu 18.10.

Přejmenujte zástupné řešení pro vyhledávání

Pokud vaše vstupní cesty nepocházejí z find, nebo pokud jste měli dost otravnosti relativní cesty, můžeme použít nějaké Perl lookahead pro bezpečné přejmenování adresářů jako v:

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

Nenašel jsem vhodný analog pro -execdir S xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file -path-before-executing/915686

sort -r Je vyžadován k zajištění toho, aby soubory přicházely za jejich příslušnými adresáři, protože delší cesty přicházejí za kratšími se stejnou předponou.