シェル スクリプト プログラムでは、変換されたファイル名がまだ存在しない場合は、ファイル名を大文字に変換する必要があります。この特定のケースでは、拡張子 (ある場合) はそのままにして、ベース名のみを大文字に変更する必要があります。
この問題を解決する私のアイデアは、まずベース名と拡張子を別々に抽出し、
tr
コマンドを使用してベース名を大文字に変換し、次に変更されたベース名と拡張子がディレクトリ内に存在するかどうかを確認することです。
存在しない場合は、mv を使用して元のファイル名を大文字のベース名に変更します。これは、まず を使用しexpr
、次に (スペース-ピリオド-スペース) を区切り文字として使用するcut
という2 つの方法で実行できると思います.
。
ベース名を抽出するためにを使用する場合expr
(たとえば、ファイル名から -python1.py
またはphonelist
)、次のように記述します。
basefile=`expr "$filename" : '\(.*\)\.*.*' `
\.*
拡張子のないファイル名にもを使用しましたが、\.*
は の 0 回以上の出現を無視するため.
、この の式はexpr
正しく機能しません。どのファイル名でも、ファイル名全体がそのまま返されます。
expr
どこが間違っているのか、どなたか説明してください。また、ファイル名から拡張子のみを抽出する方法も教えてください。
答え1
シェルが の場合bash
、bash パラメータ展開のみを使用します。
file="aaa.bbb.dat"
name=${file%.*} # delete everything after last dot
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything
echo "$upcase"
AAA.BBB.dat
より難しいケースに挑戦してみましょう:
file="déjà vu . dat "
name=${file%.*} # delete everything after last dot
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything
echo ":$upcase:"
与えるもの:
:DÉJÀ VU . dat :
それで:
- 結果を使用するまでは二重引用符は必要ありません
- 非ASCII文字でも大文字は問題ないようです
答え2
グループがどこまで拡張されるかがあいまいな場合、正規表現エンジンは最初に最長一致を優先します。任意のファイル名の場合、\(.*\)
名前全体に一致し、\.*.*
空の文字列と一致します。
拡張子ありと拡張子なしの 2 つのケースが必要になります。ファイル名が で始まる場合.
、それは拡張子の始まりではないことにも注意してください。
なぜ を使用するのか理解できませんexpr
。シェルパラメータの操作の方が簡単です。
大文字に変換する場合、tr
Linux の実装では非 ASCII ロケールがサポートされていないことに注意してください。バイト操作のみを行います。たとえば、 は ではなく になります。echo accentué | tr a-z A-Z
代わりACCENTUé
にACCENTUÉ
awk などのロケール対応ツールを使用してください。bash では を使用できます${filename^^?}
が、sh では使用できません。スクリプトがファイル名のエンコードに適したロケールで実行されていることを確認してください。
ファイル名にはディレクトリ部分が含まれていないと想定しています。含まれている場合は、まずそれを分離してください。
case $filename in
?*.*) # There is an extension
base="${filename%.*}"; ext=".${filename##*.}";;
*) # No extension
base="$filename"; ext="";;
esac
upcased_base="$(printf %s. %base | awk '$0 = toupper($0)')"
upcased="${upcased_base%.}$ext"
末尾の改行文字が削除されることにより、.
スクリプトは拡張子の直前に改行文字があるファイル名を正しく処理できるようになります。これがないと、コマンド置換によって末尾の改行文字が削除されます。ファイル名に改行文字が含まれていないことが既に確認されている場合は、これは必要ありません。%s.
$upcased_base
答え3
これは完全にawk
ベースのソリューションであり、シェル スクリプトに次の行を追加します。
uppercasename="$(echo "$filename" | awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1')"
これは.
フィールドセパレータとして使用されます入力と出力用そして、フィールドが 1 つしか見つからない場合は、それを大文字に変換し、それ以外の場合は最後のフィールドを除くすべてのフィールドを大文字に変換します。次に、結果を出力します (これは1
、 の省略表記であるの意味です{print}
)。
を使用している場合はbash
、パイプを削除して次のように記述できます。
uppercasename="$(awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1' <<< "$filename")"
here-string を使用します。
.
これは、 のように で終わるファイル名の境界線上のケースでは、myfile.this.txt.
それを「空だが存在する接尾辞」として扱い、 に変換するように設計されていることに注意してくださいMYFILE.THIS.TXT.
。また、ファイル名が始まるがあり.
、他の拡張子がない場合 ( など.myfile
)、小文字のままになります。