sed置換のLHSおよびRHSで変数を使用するにはどうすればよいですか?


61

私はやってみたいです:

cat update_via_sed.sh | sed 's/old_name/new_name/' > new_update_via_sed.sh

私のプログラムで。

しかし、変数を使用したい、例えば

old_run='old_name_952'
new_run='old_name_953'

私はそれらを使用しようとしましたが、置換は行われません(エラーなし)。私が試してみました:

cat update_via_sed.sh | sed 's/old_run/new_run/'
cat update_via_sed.sh | sed 's/$old_run/$new_run/'
cat update_via_sed.sh | sed 's/${old_run}/${new_run}/'

回答:


45

できること:

sed "s/$old_run/$new_run/" < infile > outfile

しかし、それを注意してください$old_run、正規表現として解釈されるだろうとのような変数が含まれているので、特殊文字、/または.しなければならないエスケープします。同様に、中$new_run&および\文字が特別扱いされる必要があるであろうと、あなたは脱出しなければならない/ことにし、改行文字が。

内容は場合$old_runまたは$new_runあなたのコントロール下ではありません、それはエスケープすることを実行することが重要だ、あるいはそのコードはコードインジェクションの脆弱性になります


3
私はsed paramsで一重引用符を使用していましたが、二重引用符に切り替えてファイルを機能させました。驚くばかり。
アーカシュ

それsedだけでは正規表現を使用しませんが、そうではありませんsed -Eか?
Kiwy

@Kiwy、いいえ。-e指定することでsed 電子の XPRESSIONを使用すると、複数(のように渡すことができるように、sed -e exp1 -e exp2)、またはファイルや表現の組み合わせを(sed -f file -e exp)。-Eいくつかの実装では、BREの代わりにEREを使用するようにsedに指示するので混乱するかもしれません。
ステファンシャゼル

私はタイプミスしましたが、OK、それは私が-E通常のものではなく拡張正規表現だけを習得せずにsedを使用して非常に多くの問題を抱えている理由を説明しています。説明してくれてありがとう。
-Kiwy

@Kiwy、さらに正規表現構文のいくつかの実装でサポートされるオプションについては、リンクされたQ&Aも参照してくださいsed
ステファンシャゼル

31

これはうまくいきました:

cat update_via_sed.sh | sed 's/'"$old_run"'/'"$new_run"'/'

私は同じファイルを「再利用」したいので、同様のアプローチを希望する人には実際にこれを使用します:

cat update_via_sed.sh | sed 's/'"$old_run"'/'"$new_run"'/' > new_update; mv -f new_update update_via_sed.sh

上記は、新しいファイルを作成してから、現在のファイルを削除し、新しいファイルの名前を現在のファイルに変更します。


4
cat、mv、または ''は必要ありません。特殊文字を使用する場合を除きます。だからsed -i s/"$old"/"$new"/ update_via_sed.shです。ただし、これは新旧のどの値に対しても機能しないことに注意してください。たとえば、$ oldはまだ検索であり、$ newは一部の文字が特別な意味を持つ置換パターンであるため、/などを含めることはできません。
frostschutz

1
sed -i "s/$old/$new/"(上記の注意事項を使用して)大丈夫です。sed通常、区切り文字はsコマンドの後の最初の文字と見なされます。つまり、変数にスラッシュ/が含まれているが(@)で言うことができない場合は、「s @ $ old @ $ new @」を使用できます。
ペテルフ

22

二重引用符(単一引用符ではない)である限り、sedで変数を使用できます。

sed "s/$var/r_str/g" file_name >new_file

/変数にスラッシュ()がある場合は、以下のような異なるセパレーターを使用します

sed "s|$var|r_str|g" file_name >new_file

1
二重引用符を使用する必要があると言及した場合は+1。それが私の問題でした。
speckledcarp

1
|私の場合のように使用することを含め、まさに私が探していたものは、変数にパスが含まれているので、その/中にある
-yorch

いくつかの理由で、パイプ|はMacOS 10.14で機能しましたが、他のセパレーターは好き@かどうか#はわかりませんでした。env変数にもスラッシュがありました。
davidenke

21

「インプレース」sed(-iフラグを使用)が答えでした。ペテルフに感謝します。

sed -i "s@$old@$new@" file

2
引用符が間違った場所にあります。引用符は変数を囲む必要がありますs@(シェルにとって特別ではありません)。最善の方法は、すべてを引用符で囲んでくださいsed -i "s@$old@$new@" file-iこれは標準sedオプションではないことに注意してください。
ステファンシャゼル

$このコマンドでどのようにエスケープできますか。同様に、$xxx全体として変数の値に変更します$JAVA_HOME。試しましたsed -i "s@\$xxx@$JAVA_HOME@" fileが、エラーは言うno previous regular expression
白波14年

3

man bash シングルクォートについてこれを与えます

文字を一重引用符で囲むと、引用符内の各文字のリテラル値が保持されます。バックスラッシュが先行する場合でも、単一引用符は単一引用符の間に出現しない場合があります。

コマンドラインで入力し何であれ、bashがそれを解釈し、それはあなたが使用している場合、この場合to.In送信されるようになっているプログラムに結果を送信するsed 's/$old_run/$new_run/'、bashはまず見てsed、それが中に実行可能な存在として認識し$PATH、変数。sed実行可能ファイルは、入力が必要です。Bashは入力を探し、を見つけ's/$old_run/$new_run/'ます。単一引用符は、bashの内容を解釈せずにそのまま渡すことを意味します。そのため、bashはそれらをsedに渡します。$行末でのみ発生するため、Sedはエラーを返します。

代わりに、二重引用符、つまり、を使用する場合"s/$old_run/$new_run/"、bashはこれを認識$old_runし、変数名として解釈し、置換を行います(この段階は変数展開と呼ばれます)。これはまさに私たちが求めたものです。

ただし、二重引用符は最初にbashによって解釈され、次にsedに渡されるため、二重引用符の使用には注意する必要があります。したがって、 `のような一部のシンボルは、使用する前にエスケープする必要があります。


1

フリッパントになる危険性があります-あなたは考慮しましたperl

これは、とりわけ「sed style」操作を行うのに非常に優れていますが、プログラミング機能も充実しています。

それは見える何をしている、あなたの例のように、実際にやろうとすると、番号をインクリメントされます。

それではどうですか:

#!/usr/bin/env perl
use strict;
use warnings 'all'; 

while ( <DATA> ) {
    s/old_name_(\d+)/"old_name_".($1+1)/e;
    print;
}

__DATA__
old_name_932

またはワンライナーとして-sedスタイル:

perl -pe 's/old_name_(\d+)/"old_name_".($1+1)/e'

1
$ echo $d1 | sed -i 's/zkserver1/'${d1}'/g' deva_file
sed: -e expression #1, char 26: unterminated `s' command 

$d1、私は、値を格納しています

変数の値を置き換えることができないため、次のコマンドを試してみました

echo $d1 | sed -i 's/zkserver1/'"${d1}"'/g' deva_file

に二重引用符がありません"${d1}"、それがエラーでした


-2

想定され$old_run$new_runすでに設定されています:

cat update_via_sed.sh | eval $(print "sed 's/$old_run/$new_run/g'")

これにより、画面上の変更が表示されます。必要に応じて、出力をファイルにリダイレクトできます。


-2

sedで変数を使用するには、二重引用符 ""を使用して、使用しているパターンで変数を囲みます。たとえば、a = "Hi"パターンに変数 'a'を追加する場合は、以下を使用できます。sed -n "1、/ pattern" $ {a} "pattern / p" filename


2
ここでの展開$aは引用符で囲まれていません。つまり、その値にスペースがあると、シェル内で単語分割が呼び出されます。
クサラナナンダ

-2

Perlを使用することもできます。

perl -pi -e ""s/$val1/$val2/g"" file

値にスペースが含まれる可能性のある変数を検討してください。Perl式("")の周りの空の文字列は何もしません。
クサラナナンダ

-2

文字列を破る

bad => linux文字列$ old_runを参照してください:

sed 's/$old_run/$new_run/'

良い=> linux変数$ old_runを参照してください:

sed 's/'$old_run'/'$new_run'/'

1
そして、もし$old_runまたは$new_runスペースが含まれていますか?
クサラナナンダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.