web-dev-qa-db-ja.com

ファイル名の一部のみを大文字に変換する

シェルスクリプトプログラムでは、変換されたファイル名がまだ存在しない場合、ファイル名を大文字に変換する必要があります。この特定のケースでは、拡張子(存在する場合)をそのままにして、ベース名のみを大文字に変更する必要があります。

問題を実行する私の考えは、最初にベース名と拡張子を別々に抽出し、trコマンドを使用してベース名を大文字に変換してから、変更されたベース名と拡張子がディレクトリに存在するかどうかを確認することです。

存在しない場合は、mvを使用して元のファイル名を大文字のベース名に変更します。これは2つの方法で実行できると思います。最初にexprを使用し、次にcutを区切り文字として.(スペース-ピリオド-スペース)を使用します。

ベース名を抽出するためにexprを使用したい場合(たとえば、ファイル名からpython1.pyまたはphonelistを使用)、次のように記述します。

basefile=`expr "$filename" : '\(.*\)\.*.*' ` 

\.*\.*の0回以上の出現を無視するため、拡張子のないファイル名にも.を使用しましたが、exprのこの式は機能しません正しく。ファイル名については、ファイル名全体をそのまま返します。

誰が私が間違っているのか説明してください。また、exprを使用してファイル名から拡張子のみを抽出する方法を教えてください。

3
Esha

シェルが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以外の文字でも大文字は問題ない
7
xenoid

グループの範囲が不明確な場合、正規表現エンジンは最初に最長一致を優先します。ファイル名の場合、\(.*\)は名前全体に一致し、\.*.*は空の文字列に一致します。

あなたは2つのケースが必要です:拡張子の有無にかかわらず。ファイル名が.で始まる場合、それは拡張子の始まりではないことにも注意してください。

exprを使用する理由がわかりません。シェルパラメータの操作は簡単です。

大文字に変換する際、Linuxのtr実装は非ASCIIロケールをサポートしないことに注意してください。バイト操作のみを行います。たとえば、echo accentué | tr a-z A-ZACCENTUéではなく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は、スクリプトが拡張子の直前の改行でファイル名を正しく処理することを保証します。これがないと、コマンド置換によって後続の改行が削除されます。ファイル名に改行文字が含まれていないことを確認している場合は、これは必要ありません。

これは完全に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.に変換するように設計されていることに注意してください。また、ファイル名starts.があり、他の拡張子がない場合(.myfileのように)、小文字のままになります。

0
AdminBee