sedでの環境変数の置換


202

これらのコマンドをスクリプトから実行すると、次のようになります。

#my.sh
PWD=bla
sed 's/xxx/'$PWD'/'
...
$ ./my.sh
xxx
bla

それは結構です。

しかし、実行すると:

#my.sh
sed 's/xxx/'$PWD'/'
...
$ ./my.sh
$ sed: -e expression #1, char 8: Unknown option to `s' 

私はチュートリアルで、シェルから環境変数を置き換えるには停止する必要があることを読み、$varname直接置き換えられないようにその部分を「引用」します。これは私がやったことであり、変数が直前に定義されている場合にのみ機能します。

$varシェルで定義されているsedを環境変数として認識させるにはどうすればよいですか?


4
$ PWDには、置換コマンドを終了する/が含まれています。
デロベルト09

@derobert:tnx。ソリューションの1つはこれに対処します...
RomanM '25

4
set -xシェルで使用して、コマンドを実行する直前にシェルに各コマンドをエコーさせます。これにより、多くの混乱が解消されます。(また、私はしばしば、set -u未設定の変数を逆参照することをハードエラーにするために使用します(参照してくださいset -e))
bobbogo

私は、プロセステーブルに値を漏洩しないように、環境変数を扱うためのsedのための方法を見つけるために望んでいたように思えるすべてにこのスレッドでの回答に従って秘密インストールするための間違ったツールであるsedの
ThorSummoner

回答:


302

2つの例は同一に見えるため、問題の診断が難しくなります。潜在的な問題:

  1. 次のように二重引用符が必要な場合があります sed 's/xxx/'"$PWD"'/'

  2. $PWDスラッシュが含まれている場合があります。その場合、区切り文字として使用するために含まれていない文字を見つける必要があります$PWD

両方の問題を一度に解決するには、おそらく

sed 's@xxx@'"$PWD"'@'

しかし、パス名に表示されないことが確実にわかっている使用可能な文字は何ですか?
RomanM 2009

5
@#%!ケース式で確認して、$ PWDにそれらがあるかどうかを確認します。たとえば、@の "$ PWD"の場合);; *)delim = "@" ;; esac; $ delimが空でなくなるまで繰り返します。
ノーマンラムジー

二重引用符を使用する代わりに別の方法があります。以下の私の答えを参照してください。
Thales Ceolin 2014

sedには別の区切り文字を使用できます。/を使用する必要はありません。また、環境変数がURLの場合も使用できます。
Guchelkaben

123

Norman Ramseyの回答に加えて、文字列全体を二重引用符で囲むことができることを付け加えておきます(これにより、ステートメントが読みやすくなり、エラーが発生しにくくなります)。

したがって、「foo」を検索して$ BARの内容で置き換える場合は、sedコマンドを二重引用符で囲みます。

sed 's/foo/$BAR/g'
sed "s/foo/$BAR/g"

最初の$ BARは正しく展開されませんが、2番目の$ BARは正しく展開されます。


4
これは二重引用符、単一引用符などをいじりよりもきれいです
Vladislavs Dovgalecs

これは、このコマンドで環境変数を正しく展開するために使用する必要があったものです。sed-i "s / 127.0.0.1 / 127.0.0.1 localhost $ HOSTNAME /" hosts
izikandrw

2
これはきちんとしているが、あなたのようないくつかのより複雑な置換、やりたいときには動作しない"2,$s/^/$foo/"ように$s、あまりにも変数として解釈されますが、それはいけません。
mjp

59

「/」以外の文字を代わりに使用できます。

sed "s#$1#$2#g" -i FILE

私の特定のケースでは、$ 2はファイルパスだったので、$ 2の内容のsedを解釈するためにバーフが発生しました/。これはまさに私がそれを乗り越えるために必要なものでした。素晴らしいヒントをありがとう!
Boyd Hemphill、2015

54

別の簡単な代替案:

$PWDは通常スラッシュが含まれるため、sedステートメントの代わりにを/使用します。|/

sed -e "s|xxx|$PWD|"

4
「二重引用符を使用する代わりに」とおっしゃっていましたが、この例では二重引用符を使用していますか?
Jeach

ポイントは、二重引用符を直接使用しないこと$PWDです...?
クリスチャン、

14

質問を編集すると、問題がわかります。現在のディレクトリが/home/yourname ...であるとしましょう...この場合、以下のコマンド:

sed 's/xxx/'$PWD'/'

に拡張されます

sed `s/xxx//home/yourname//

これは無効です。これを行う場合は、$ PWDの\各文字の前に文字を置く必要があり/ます。


しかし、PWDはシェルによって定義されます... $ PWDをエコーする場合、pwdを取得します
RomanM '25

1
では、環境変数をどのようにエスケープしますか?
アインポクルム2014

1
選択した回答は回避策を説明しています...区切り文字にスラッシュを使用しないでください
エディ

現在の作業ディレクトリに他の文字が含まれるとすぐに問題になります。
blubberdiblub 2014年

6

悪い方法:区切り文字を変更する

sed 's/xxx/'"$PWD"'/'
sed 's:xxx:'"$PWD"':'
sed 's@xxx@'"$PWD"'@'

多分それらは最終的な答えではありません、

で発生する文字がわからない$PWD/ :または@

の良い方法は、の特殊文字を置き換えること$PWDです。

良い方法:区切り文字をエスケープする

例:URL$ urlとして置き換えようとします(: /コンテンツ内にあります)

x.com:80/aa/bb/aa.js

文字列$ tmp内

<a href="URL">URL</a>

a。/区切り文字として使用

echo ${url//\//\\/}
x.com:80\/aa\/bb\/aa.js

echo ${url//\//\/}
x.com:80/aa/bb/aa.js

echo "${url//\//\/}"
x.com:80\/aa\/bb\/aa.js

echo $tmp | sed "s/URL/${url//\//\\/}/"
<a href="x.com:80/aa/bb/aa.js">URL</a>

echo $tmp | sed "s/URL/${url//\//\/}/"
<a href="x.com:80/aa/bb/aa.js">URL</a>

または

b。:区切り文字として使用(より読みやすい/

echo ${url//:/\:}
x.com:80/aa/bb/aa.js

echo "${url//:/\:}"
x.com\:80/aa/bb/aa.js

echo $tmp | sed "s:URL:${url//:/\:}:g"
<a href="x.com:80/aa/bb/aa.js">x.com:80/aa/bb/aa.js</a>

3

実際、(少なくともgnu sedで)最も単純なことは、sed置換(s)コマンドに別のセパレーターを使用することです。したがって、s / pattern / '$ mypath' /がs / pattern // my / path /に展開される代わりに、当然sコマンドを混乱させるのではなく、s!pattern! '$ mypath'!これは、s!pattern!/ my / path!に展開されます。私は、区切り文字として通常の、しかし選択の余地のないスラッシュを避けるために、強打(!)文字(または好きなものを使用)を使用しました。


3
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1' 

VARには、フィールドを置き換えるものを含めます


3

sed内の変数の処理

[root@gislab00207 ldom]# echo domainname: None > /tmp/1.txt

[root@gislab00207 ldom]# cat /tmp/1.txt

domainname: None

[root@gislab00207 ldom]# echo ${DOMAIN_NAME}

dcsw-79-98vm.us.oracle.com

[root@gislab00207 ldom]# cat /tmp/1.txt | sed -e 's/domainname: None/domainname: ${DOMAIN_NAME}/g'

 --- Below is the result -- very funny.

domainname: ${DOMAIN_NAME}

 --- You need to single quote your variable like this ... 

[root@gislab00207 ldom]# cat /tmp/1.txt | sed -e 's/domainname: None/domainname: '${DOMAIN_NAME}'/g'


--- The right result is below 

domainname: dcsw-79-98vm.us.oracle.com

これをAzure DevOps YAMLパイプラインで機能させるのに苦労していました。このコメントは、このトリックを使用していくつかの構成ファイルをトークン化するのに役立ちました。
アンドフ

1

同様の問題があり、リストがあり、テンプレートに基づいてSQLスクリプトを作成する必要があります(@INPUT@置換する要素として含まれています)。

for i in LIST 
do
    awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.