GNU/Linux >> Znalost Linux >  >> Linux

Převeďte všechny přípony souborů na malá písmena

S tímto příkazem jsem uspěl.

rename JPG jpg *.JPG

Kde rename je příkaz, který říká shellu, aby přejmenoval každý výskyt JPG do jpg v aktuální složce se všemi názvy souborů s příponou JPG .

Pokud vidíte, že Bareword "JPG" není povoleno, zatímco "strict subs" je používáno na (hodnota 1) řádku 1 s tímto přístupem, zkuste:

rename 's/\.JPG$/.jpg/' *.JPG

Řešení

Úlohu můžete vyřešit v jednom řádku:

find . -name '*.*' -exec sh -c '
  a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

Poznámka:toto se přeruší u názvů souborů, které obsahují nové řádky. Ale zatím se mnou mějte strpení.

Příklad použití

$ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT
$ find .
.
./C
./C/D.TXT
./1.TXT
./a.TXT
./B.TXT

$ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

$ find .
.
./C
./C/D.txt
./a.txt
./B.txt
./1.txt

Vysvětlení

Všechny soubory najdete v aktuálním adresáři (. ), které mají tečku . ve svém názvu (-name '*.*' ) a spusťte příkaz pro každý soubor:

a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"

Tento příkaz znamená:zkuste převést příponu souboru na malá písmena (to znamená sed ):

$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt

a výsledek uložte do a proměnná.

Pokud se něco změnilo [ "$a" != "$0" ] , přejmenujte soubor mv "$0" "$a" .

Název zpracovávaného souboru ({} ) předán sh -c jako jeho další argument a na příkazovém řádku je vidět jako $0 .To dělá skript bezpečným, protože v tomto případě shell bere {} jako data, nikoli jako část kódu, jako když je specifikován přímo v příkazovém řádku.(Děkuji @gniourf_gniourf za upozornění na tento opravdu důležitý problém ).

Jak můžete vidět, pokud použijete {} přímo ve skriptu je možné mít v názvech souborů nějaké shell-injekce, něco jako:

; rm -rf * ;

V tomto případě bude vkládání považováno shellem za součást kódu a budou provedeny.

Zatímco-verze

Jasnější, ale o něco delší verze skriptu:

find . -name '*.*' | while IFS= read -r f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Toto se stále přeruší u názvů souborů obsahujících nové řádky. Chcete-li tento problém vyřešit, musíte mít find který podporuje -print0 (jako GNU find ) a Bash (takže read podporuje -d oddělovací spínač):

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Toto stále nefunguje u souborů, které obsahují koncové nové řádky (protože je pohltí a=$(...) subshell. Pokud opravdu chcete spolehlivou metodu (a měli byste!) s nejnovější verzí Bash (Bash≥4.0), která podporuje ,, rozšíření parametrů zde je konečné řešení:

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  base=${f%.*}
  ext=${f##*.}
  a=$base.${ext,,}
  [ "$a" != "$f" ] && mv -- "$f" "$a"
done

Zpět k původnímu řešení

Nebo v jednom find přejít (zpět k původnímu řešení s několika opravami, díky kterým je opravdu spolehlivé):

find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

Přidal jsem -type f takže se přejmenovávají pouze běžné soubory. Bez toho můžete mít stále problémy, pokud jsou názvy adresářů přejmenovány před názvy souborů. Pokud chcete také přejmenovat adresáře (a odkazy, roury atd.), měli byste použít -depth :

find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

takže find provede prohledávání do hloubky.

Můžete namítnout, že není efektivní vytvořit bash proces pro každý nalezený soubor. To je správně a předchozí verze smyčky by pak byla lepší.


Toto je kratší, ale obecnější v kombinaci s odpovědí ostatních:

rename 's/\.([^.]+)$/.\L$1/' *

Simulace

Pro simulaci použijte -n , tj. rename -n 's/\.([^.]+)$/.\L$1/' * . Tímto způsobem můžete vidět, co se změní, než budou provedeny skutečné změny. Příklad výstupu:

Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg
Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg
rAnD0m.jPg1 renamed as rAnD0m.jpg1

Krátké vysvětlení syntaxe

  • Syntaxe je rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
  • \.([^.]+)$ znamená posloupnost čehokoli kromě tečky ([^.] ) na konci řetězce ($ ), za tečkou (\. )
  • .\L$1 znamená tečku (\. ) následované malými písmeny (\L ) z 1 skupiny ($1 )
  • První skupinou je v tomto případě rozšíření ([^.]+ )
  • Raději použijte jednoduché uvozovky ' místo dvojitých uvozovek " zabalit regulární výraz, aby se zabránilo expanzi shellu

Linux
  1. Jak odebrat všechny soubory ve složce kromě jednoho konkrétního souboru v systému Linux

  2. Jak převést textové soubory na všechna velká nebo malá písmena

  3. Jak najdu všechny odlišné přípony souborů v hierarchii složek?

  1. symbolický odkaz:najít všechny soubory, které odkazují na tento soubor

  2. Jak převést ISO8859-15 na UTF8?

  3. Změna všech přípon souborů ve složce pomocí CLI v Linuxu

  1. V shellu převeďte .txt na .csv

  2. formát souboru s hesly ldapsearch

  3. Získejte všechny přípony a jejich příslušný počet souborů v adresáři