変数の純粋なシェル複合置換

変数の純粋なシェル複合置換

逆参照を使用しても、複数のパターンの変数のテキストを同時に置き換える方法はありますか?

たとえば、FILE=filename.extに変更したいのですがfilename_sometext.ext、ファイル拡張子が何であるかわかりません.ext。私が知っているのは、拡張子が最後の点の後ろにあるということだけです。したがって、2つのステップで行うことができます。

EXT=${FILE##*.}
FILE=${FILE%.*}_sometext.$EXT

1つのステップで完了できますか(例:${FILE/.\(*\)/_sometext.\1}[これは機能しません])?

sedしかし、/などのない純粋なawkシェルでこれを行う必要があります。私のシェルはですがksh、bashismsでこれを行う方法があればそれも知りたいです。

答え1

Bash パラメータ拡張表現変数(FILE例では)はパラメータ名でなければなりません。だから彼らは巣を作らない。最後の部分は${param/pattern/replacement}文字列でなければなりません。したがって、逆参照はサポートされていません。

私の唯一の提案は、以下を使用することです。

${EXT:+.$EXT}

ファイルに拡張子がない場合に後ろにドットを追加したくない場合。


修正する

明らかに逆参照がサポートされていますクッシュ 93

だからあなたは次のようなものを使うことができます

FILE="${FILE/@(.*)/_something\1}"

答え2

FILE=${FILE%.*}_sometext.${FILE##*.}この特別なケースでは、それがそれを行うと思います。

答え3

変わりやすい。

すべてのシェルで変数または値を連結できます。

$ a=One; b=Two; c=Three
$ d="$a$b$c"; echo $d
OneTwoThree

この${parameter%word}構造POSIXですほとんどのシェルは長い間この機能をサポートしてきました。
前提として、FILE=filename.ext次のようにすることができます。

$ FILE="${FILE%.*}_sometext.${FILE##*.}"; echo "$FILE"
filename_sometext.ext

これは(要求どおり)1行で、ほとんどのシェルで機能します。


変数を使用することも可能です(複数の点がある場合でも)。

#!/bin/bash
FILE=file.one.name.ext
ADDTEXT="_sometext"
EXT="${FILE##*.}"
echo "EXT=$EXT"
echo "final FILE=${FILE%.*}${ADDTEXT}.$EXT"

または、次の1行だけを使用してください。

ONEFILE=${FILE%.*}${ADDTEXT}.${FILE##*.}
echo "one   FILE=$ONEFILE"

パターン交換

トリッキーな部分は、${parameter/pattern/string}「パターン置換」を使用しようとすることです。

変数は多くのシェルで動作します(ビジボックスの再作成も含む)。

NEWTEXT="${ADDTEXT}.${FILE##*.}"
echo "ash   FILE=${FILE/.*/${NEWTEXT}}"

しかし、古いshElsではそうではありません。


以下でのみ機能しますFILE=filename.ext
bash(およびksh、ksh93、mksh、zsh)では機能しますが、ash、dash、sh、またはcshでは機能しません。

echo "bash  FILE=${FILE/%.*/${ADDTEXT}.${FILE##*.}}"

%引数の終わりに一致を表示するために文字を使用することに注意してください(ただし、残念ながら貪欲なので、すべてのポイントを食べてしまいますFILE=file.one.name.ext)。

結論として

置換がどれほど貪欲であるかを制御する最も良い方法は、別の変数を使用することです(「パターン置換」のいくつかの変数の代わりに)。

答え4

FILE="${FILE%.*}_sometext${FILE#"${FILE%.*}"}"

シェル変数に$FILEa が含まれている場合、上記のコマンドは前の.値から最後の値以降の.すべての値を引いた値を再割り当てします。_sometextそして、最後の前の値.とそれ以降のすべての値を維持します。

だから:

FILE=some.dot
FILE="${FILE%.*}_sometext${FILE#"${FILE%.*}"}"
printf %s\\n "$FILE"

some_sometext.dot

シェル変数が$FILE次の場合いいえ点が含まれている場合_sometext文字列は前の値の終わりにのみ追加されます。

FILE=no_dots_at_all
FILE="${FILE%.*}_sometext${FILE#"${FILE%.*}"}"
printf %s\\n "$FILE"

no_dots_at_all_sometext

これは、私が行ったようにパラメータ拡張を入れ子にしない場合に発生する可能性のある動作との重要な違いです。

FILE=no_dots_at_all
FILE="${FILE%.*}_sometext${FILE##*.}"
printf %s\\n "$FILE"

no_dots_at_all_sometextno_dots_at_all

パラメータ拡張をネストすると内部から外部に評価されるため、最初に発生することは次のとおりです。

for    FILE in    some.dot no_dots_at_all
do     printf %s\\n '${FILE#'"${FILE%.*}"'}'
done

${FILE#some}
${FILE#no_dots_at_all}

...シェルは一致するすべてのビットを削除し、残りを外部拡張から削除されたパターンとして使用します。だから、いいえ一致するビットと変数は完全に拡張され、外部拡張は削除されます。みんな変数の値を式に2回置き換える代わりに使用します。

関連情報