スラッシュを含む変数をsedに渡す方法


100

スラッシュを含む変数をパターンとしてどのように渡しsedますか?

たとえば、次の変数があるとします。

var="/Users/Documents/name/file"

私はそれを次のsedように渡したいです:

sed "s/$var/replace/g" "$file"

ただし、エラーが発生します。どうすれば問題を回避できますか?

回答:


193

sed任意の区切り文字(制御文字を含む)を使用できるように、代替の正規表現区切り文字を使用します。

sed "s~$var~replace~g" $file

2
動作しません。私はsed -i "s〜blah〜$ var〜g file"を試して、「sed -e expression#1、char 70:unterminated `s 'command」を取得します。私は犯人が$ varのスラッシュであることを確認しました。これに対するこのソリューションのバリエーションは至る所にあり、どれも機能しません。sedは最近更新されましたか?Ubuntu 14.04.4 LTSのv4.2.2を使用しています。
Paul Ericson、2016

それは何の価値なのかによって異なります$var
anubhava

1
@PaulEricsonが観察したように〜で動作しませんが、まだ動作します|
Kenny Ho

1
最後に「〜」(G後)少なくともAWSアマゾンLinuxの場合、必要とされていないようです(CentOSのベース)
ソール・マルティネスVidals

1
あなたは私の日を保存しました
user7131571

61

純粋なbashの答え:パラメーター展開を使用して、変数内のスラッシュをバックスラッシュでエスケープします。

var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file

1
これは、どの文字に変数が含まれているかが常にわからないため、良い方法です。したがって、疑わしい場合はいつでもsed区切り文字をエスケープできます。たとえば、次のようになります。sed "s:$ {var //:/ \\:}:replace:g" $ file
Stephane L

綺麗な。私のいくつかの名前変更スクリプトをよりきれいにしました。
クラウド

今日は美しいものを学びました、ありがとう。受け入れられる答えでなければなりません。
スティーブケレット

6
ここで使用されているパターンのいくつかの明快さ:${parameter/pattern/string}。したがって、この場合、パラメータはvar、パターンは/\/、文字列は\\/です。パターンがで始まるため、パターンのすべてのインスタンスが置き換えられ/ます。
Josh

1
@josh、したがって、パターンの先頭のスラッシュは実際には置き換えるパターンの一部ではありません。
グレンジャックマン

32

これを行う別の方法は、anubhavaの答えよりも醜いですが、var別のsedコマンドを使用してすべてのバックスラッシュをエスケープすることです。

var=$(echo "$var" | sed 's/\//\\\//g')

その後、これは動作します:

sed "s/$var/replace/g" $file

12

/in sedを区切り文字として使用すると、置換されたときに変数のスラッシュと競合し、結果としてエラーが発生します。これを回避する1つの方法は、その変数内の任意の文字から一意の別の区切り文字を使用することです。

var="/Users/Documents/name/file"

あなたは機会に適したoctorsopeキャラクター(または/使いやすさではない他のキャラクター)を使用できます

sed "s#$var#replace#g" 

または

sed 's#$'$var'#replace#g'

これは、変数にスペースが含まれていない場合に適しています

または

sed 's#$"'$var'"#replace#g'

コマンド全体を二重引用符で囲むのと比較して、変数内の何でも置換することに関心があるので、上記を使用する方が賢明です。


動作しません。私はsed -i "s〜blah〜$ var〜g file"を試して、「sed -e expression#1、char 70:unterminated `s 'command」を取得します。私は犯人が$ varのスラッシュであることを確認しました。これに対するこのソリューションのバリエーションは至る所にあり、どれも機能しません。sedは最近更新されましたか?Ubuntu 14.04.4 LTSのv4.2.2を使用しています。
Paul Ericson、2016

@PaulEricson私が利用できるUbuntuでこれを再現することはできません。$varcontainsの場合、~明らかに別の区切り文字を選択する必要があります。「終了していない」エラー$varは、改行が含まれているように聞こえます。値のすべての改行をバックスラッシュでエスケープすることで修正できるかもしれませんが、これは完全に移植性があるとは思いません。これは概して、値のスラッシュの問題とは無関係です。
tripleee 2018

@PaulEricsonああ、あなたの引用は正しくありません。引用符の中にファイル名を入れるべきではありません。sed -i "s~blah~$var~g" file実際のsedスクリプトのみを引用符で囲みます。
Tripleee

5

これは古い質問ですが、ここでの答えはどれも、操作s/from/to/については詳しく説明していません。

sedステートメントの一般的な形式は次のとおりです。

*address* *action*

ここで、addressは正規表現の範囲または行番号の範囲(または空の場合、アクションはすべての入力行に適用されます)です。だから例えば

sed '1,4d' file

1行目から4行目までを削除しますアドレスは行番号の範囲1,4で、アクションd削除コマンドです)。そして

sed '/ick/,$s/foo/bar/' file

正規表現の最初の一致とファイルの終わりの間の任意の行で、の最初の出現をfooで置き換えます(アドレスは範囲であり、アクションは代替コマンドです)。barick/ick/,$ss/foo/bar/

このコンテキストでickは、変数からのものである場合、次のことができます

sed "/$variable/,\$s/foo/bar/"

(シェルが変数を補間できるように、単一引用符ではなく二重引用符を使用していることに注意してください。二重引用符内にリテラルドル記号を引用符で囲む必要があります)変数にスラッシュが含まれている場合、構文エラーが発生します。(シェルは変数を展開し、結果の文字列をに渡しsedます。そのためsed、リテラルテキストのみが表示されます-シェルの変数の概念はありません。)

解決策は、別の区切り文字を使用することです(変数の値に出現できない文字を使用できる必要があることは明らかです)が、s%foo%bar%ケースとは異なり、別の区切り文字を使用する場合は、区切り文字の前にバックスラッシュも必要です。デフォルトよりも区切り文字/

sed "\\%$variable%,\$s/foo/bar/" file

(単一引用符内では、単一のバックスラッシュで明らかに十分です); または、値のすべてのスラッシュを個別にエスケープすることができます。この特定の構文はBashのみです。

sed "/${variable//\//\\/}/,\$s/foo/bar/" file

または、別のシェルを使用している場合は、

escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file

明確にするため$variableに、文字列が含まれている場合1/2、上記のコマンドは次と同等になります。

sed '\%1/2%,$s/foo/bar/' file

最初のケースでは、そして

sed '/1\/2/,$s/foo/bar/' file

第二に。


4

マクロを展開するだけでなく、変数がファーストクラスのシチズンであるPerlを使用します。

var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
  • -p 入力を行ごとに読み取り、処理後に行を出力します
  • \Q次の文字列内のすべてのメタ文字を引用符で[囲みます(ここに表示される値には必要ありませんが、値が含まれている場合、または通常の表現に特別な他の値がある場合は必要です)

Stack Exchange全体で数十の「sed式で変数を使用する」質問に対する唯一の一般的に役立つ回答。それ以外はすべて、事実上「sedにとって特別なものをエスケープする」ものであり、変数やsedの可変性を考えると、実際には役に立たない。
ヒースラフター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.