拡張機能が何であるかに関係なく、すべての拡張機能を小文字にしようとしています。これまでのところ、私が見てきたことから、小文字に変換するファイル拡張子を指定する必要があります。ただし、名前の最初の最後のドットの後のすべてを小文字にしたいだけです.
。
どうすればそれを行うことができbash
ますか?
拡張機能が何であるかに関係なく、すべての拡張機能を小文字にしようとしています。これまでのところ、私が見てきたことから、小文字に変換するファイル拡張子を指定する必要があります。ただし、名前の最初の最後のドットの後のすべてを小文字にしたいだけです.
。
どうすればそれを行うことができbash
ますか?
解決
1行でタスクを解決できます。
find . -name '*.*' -exec sh -c '
a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "$0" "$a" ' {} \;
注:これは、改行を含むファイル名では機能しなくなります。しかし、今のところ私に耐えてください。
使用例
$ 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
説明
名前( ).
にピリオドが含まれる現在のディレクトリ()内のすべてのファイルを検索し、ファイルごとにコマンドを実行します。.
-name '*.*'
a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"
そのコマンドは次のことを意味します:ファイル拡張子を小文字に変換しようとします(それはになりますsed
):
$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt
a
結果を変数に保存します。
何かが変更された場合は[ "$a" != "$0" ]
、ファイルの名前を変更しますmv "$0" "$a"
。
追加の引数として{}
渡される処理中のファイルの名前( )であり、コマンドライン内では。として表示されます。この場合、シェルは{}をコマンドラインで直接指定されている場合のようにコード部分としてではなく、データとして受け取るため、スクリプトを安全にします。(この本当に重要な問題を指摘してくれた@gniourf_gniourfに感謝します)。sh -c
$0
ご覧のとおり{}
、スクリプトで直接使用する場合は、ファイル名に次のようなシェルインジェクションを含めることができます。
; rm -rf * ;
この場合、インジェクションはシェルによってコードの一部と見なされ、実行されます。
Whileバージョン
より明確ですが、少し長いバージョンのスクリプト:
find . -name '*.*' | while IFS= read -r f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done
これは、改行を含むファイル名では引き続き機能します。この問題を修正するには、(GNUのように)とBash(区切り文字スイッチをサポートするため)find
をサポートするが必要です。-print0
find
read
-d
find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done
これは、末尾の改行を含むファイルではまだ壊れています(a=$(...)
サブシェルによって吸収されるためです。本当に,,
確実な方法が必要な場合(そしてそうする必要があります!)、パラメーター拡張をサポートする最新バージョンのBash(Bash≥4.0)を使用します。究極の解決策:
find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
base=${f%.*}
ext=${f##*.}
a=$base.${ext,,}
[ "$a" != "$f" ] && mv -- "$f" "$a"
done
元のソリューションに戻る
または、一度find
に(元のソリューションに戻って、それを本当に確実にするいくつかの修正を加えます):
find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;
-type f
通常のファイルのみの名前が変更されるように追加しました。これがないと、ファイル名の前にディレクトリ名の名前を変更すると、問題が発生する可能性があります。ディレクトリ(およびリンク、パイプなど)の名前も変更する場合は、次を使用する必要があります-depth
。
find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;
find
深さ優先探索を実行します。
bash
見つかったファイルごとにプロセスを生成するのは効率的ではないと主張するかもしれません。それは正しいです、そして以前のループバージョンはそれからより良いでしょう。
このコマンドで成功しました。
rename JPG jpg *.JPG
ここに、現在のフォルダ内のすべてのファイル名の名前を拡張子が.でrename
あるに変更するようにシェルに指示するコマンドがあります。JPG
jpg
JPG
このアプローチで(eval 1)行1で「strictsubs」が使用されているときにベアワード「JPG」が許可されていない場合は、次のことを試してください。
rename 's/\.JPG$/.jpg/' *.JPG
これはより短いですが、より一般的であり、他の人の答えと組み合わされています。
rename 's/\.([^.]+)$/.\L$1/' *
シミュレーション
シミュレーションには-n
、すなわちを使用しますrename -n 's/\.([^.]+)$/.\L$1/' *
。このようにして、実際の変更が実行される前に何が変更されるかを確認できます。出力例:
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
構文についての簡単な説明
rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
\.([^.]+)$
[^.]
文字列()の最後、ドット()$
の後のドット(\.
)以外のシーケンスを意味します.\L$1
ドット( )の後に最初のグループ()の\.
小文字()が続くことを意味します\L
$1
[^.]+
)です'
には、二重引用符ではなく一重引用符を使用することをお勧めします"
このスニペットは、必要な代替手段のコアとして使用できます。
#!/bin/bash
# lowerext.sh
while read f; do
if [[ "$f" = *.* ]]; then
# Extract the basename
b="${f%.*}"
# Extract the extension
x="${f##*.}"
# Convert the extension to lower case
# Note: this only works in recent versions of Bash
l="${x,,}"
if [[ "$x" != "$l" ]]; then
mv "$f" "$b.$l"
fi
else
continue
fi
done
その後、あなたがする必要があるのは、あなたがその標準的な入力に名前を変更する必要があるファイルのリストを供給することです。たとえば、現在のディレクトリと任意のサブディレクトリの下にあるすべてのファイルの場合:
find -type f | lowerext.sh
小さな最適化:
find -type f -name '*.*' | lowerext.sh
これよりも具体的な答えが必要な場合は、より具体的にする必要があります...
ZSHを使用している場合:
zmv '(*).(*)' '$1.$2:l'
取得した場合はzsh: command not found: zmv
、単に実行します。
autoload -U zmv
そして、もう一度やり直してください。
zmvに関するヒントについてのこの元の記事と、小文字/大文字の置換構文に関するZSHドキュメントに感謝します。
これはあなたの'.mp3のために仕事をします-しかし作業ディレクトリでのみ-しかし空白でファイル名を消費することができます:
for f in *.[mM][pP]3; do mv "$f" "${f%.*}.mp3"; done
修正:
for f in *.[mM][pP]3; do [[ "$f" =~ \.mp3$ ]] || mv "$f" "${f%.*}.mp3"; done
すべての1つの優れたソリューションに対して再帰的に:
find -name '*.JPG' | sed 's/\(.*\)\.JPG/mv "\1.JPG" "\1.jpg"/' |sh
上記は、拡張子が「JPG」のファイルの名前を、拡張子が「jpg」のファイルに再帰的に変更します。
mmv
(=複数のファイルを移動する)がインストールされていて、ファイル名に含まれるドットが最大1つである場合は、次を使用できます。
mmv -v "*.*" "#1.#l2"
右に1つ以上のドットを取得することはありませんが(の一致するアルゴリズム*
は貪欲ではないためmmv
)、正しく処理さ()
れ'
ます。例:
$ mmv -v "*.*" "#1.#l2"
FOO.BAR.MP3 -> FOO.bar.mp3 : done
foo bar 'baz' (CD 1).MP3 -> foo bar 'baz' (CD 1).mp3 : done
完璧ではありませんが、すべてのものよりもはるかに使いやすく、覚えやすいfind/exec/sed
です。
すべての大文字の「JPG」拡張子を小文字の「jpg」に変換するなど、特定のファイル拡張子にのみ関心がある場合は、コマンドラインユーティリティの名前をそのように変更できます。変更するディレクトリにCDを挿入します。それで
rename -n 's/\.JPG$/\.jpg/' *
-nオプションを使用して何が変更されるかをテストし、結果に満足したら、そのようにせずに使用します
rename 's/\.JPG$/\.jpg/' *
私はこれを行うための簡単な方法を(それについて考える必要なしに)探していましたが、最終的にそれを考え抜いて、これを思いつきました(確かに、元の投稿のずっと後)
find . -name \\*.JPG -print -exec rename s/.JPG/.jpg/ {} \\;
私はそれを約60千のファイルで実行し、正常に動作しましたが、もちろん、-n
最初にテストしたい場合は、「名前の変更」オプションを使用できます。
したがって、ラインノイズのように見えるこれらのソリューションは素晴らしいものですが、これはpython REPLから簡単に実行できます(OPがbashを要求したことは知っていますが、Pythonは最近bashを使用する多くのシステムにインストールされています... )::
import os
files = os.listdir('.')
for f in files:
path, ext = os.path.splitext(f)
if ext.isupper():
os.rename(f, path + ext.lower())