複雑なテキストファイルでシェル変数を置き換える方法


89

シェル変数(たとえば、$ VAR1または$ VAR2)を導入したテキストファイルがいくつかあります。

それらのファイルを(1つずつ)取得して、すべての変数が置き換えられた新しいファイルに保存したいと思います。

これを行うために、私は次のシェルスクリプト(StackOverflowにあります)を使用しました:

while read line
do
    eval echo "$line" >> destination.txt
done < "source.txt"

これは非常に基本的なファイルで非常にうまく機能します。

しかし、より複雑なファイルでは、「eval」コマンドはあまりにも多くのことを行います。

  • 「#」で始まる行はスキップされます

  • XMLファイルの解析は大量のエラーを引き起こします

それを行うためのより良い方法はありますか?(シェルスクリプトでは...これはたとえばAntで簡単に実行できることを私は知っています)

敬具

回答:


206

見てみると、私のシステムにはenvsubstgettext-baseパッケージの一部であるコマンドがあることがわかりました。

だから、これはそれを簡単にします:

envsubst < "source.txt" > "destination.txt"

両方に同じファイルを使用する場合はsponge、Johnny Utahhが提案しているように、moreutilのようなものを使用する必要があることに注意してくださいenvsubst < "source.txt" | sponge "source.txt"。(シェルリダイレクトは、ファイルを読み取る前にファイルを空にするためです。)


4
すごい!ただし、環境変数に対してのみ機能します。.shスクリプトで宣言されている変数でそれを機能させるにはどうすればよいですか?
ベン

12
@Ben
envsubstで

9
envsubstGNU gettextの
Andy

3
@user_mda出力が送信されます。
derobert 2015年

4
警告:変数展開以外の文字source.txtが含まれている場合$envsubstこれらも置き換えられ、をエスケープする方法はありません$。一般的な(醜い)回避策はexport DOLLAR="$"です。
コス

67

回答2を参照して、envsubstについて話し合うときに、次のように質問しました。

.shスクリプトで宣言されている変数でそれを機能させるにはどうすればよいですか?

答えは、を呼び出す前に変数をエクスポートする必要があるということですenvsubst

envsubst SHELL_FORMAT引数を使用して、入力で置換する変数文字列を制限することもできます(入力内の文字列が、共通のシェル変数値で意図せずに置換されるのを回避します-例$HOME)。

例えば:

export VAR1='somevalue' VAR2='someothervalue'
MYVARS='$VAR1:$VAR2'

envsubst "$MYVARS" <source.txt >destination.txt

すべてのインスタンスを置き換えます$VAR1$VAR2(とのみVAR1VAR2)内source.txt'somevalue'し、'someothervalue'それぞれ。


15
'設定に使用される一重引用符MYVARSは非常に重要です
Mark Lakata 2015

なおexportenvsubstまたはテキスト・ツー・代替が大きい場合、任意のインターリーブコマンドが失敗する可能性があります。参照。
ビショップ

@ramは、SHELL_FORMAT引数(ie "$MYVARS")を省略すると、エクスポートされたすべての変数が置換されるためです。それがあなたが必要とするものなら、心配はありません。
チアゴフィゲイロ2018年

14

このトピックが古いことは知っていますが、変数をエクスポートせずに、より簡単に機能するソリューションがあります。ワンライナーにすることもできますが、私\はオンラインエンドを使用して分割することを好みます。

var1='myVar1'\
var2=2\
var3=${var1}\
envsubst '$var1,$var3' < "source.txt" > "destination.txt"

#         ^^^^^^^^^^^    ^^^^^^^^^^     ^^^^^^^^^^^^^^^
# define which to replace   input            output

変数envsubstは、環境変数と見なされるために、同じ行に定義する必要があります。

'$var1,$var3'必ず指定のものを交換するオプションです。${VARIABLE_USED_BY_JENKINS}置き換えてはならない入力ファイルを想像してみてください。


8
  1. ENV変数を定義する
$ export MY_ENV_VAR=congratulation
  1. 次の内容のテンプレートファイル(in.txt)を作成します
$MY_ENV_VAR

(Linuxの場合)$ TERM、$ SHELL、$ HOME ...など、システムで定義されている他のすべてのENV変数を使用することもできます。

  1. このコマンドを実行して、in.txtファイル内のすべての環境変数を置き換え、結果をout.txtに書き込みます。
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
  1. out.txtファイルの内容を確認してください
$ cat out.txt

「おめでとう」と表示されます。


0

本当にbash(およびsed)のみを使用したい場合は、各環境変数(setposixモードで返される)を調べ-e 'regex'て、そこからsedの束を作成し、で終了して-e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g'から、すべてをに渡します。 sed。

ただし、Perlの方がうまく機能します。配列として環境変数にアクセスでき、実行可能ファイルの置換を実行できるため、環境変数を1回だけ照合できます。


なぜ誰かがこのような答えに反対票を投じるのですか?-perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' "$main_tf_file"
Yordan Georgievの

0

実際にあなたが変更する必要があるreadread -r、それはバックスラッシュを無視行います。

また、引用符と円記号はエスケープする必要があります。そう

while read -r line; do
  line="${line//\\/\\\\}"
  line="${line//\"/\\\"}"
  line="${line//\`/\\\`}"
  eval echo "\"$line\""
done > destination.txt < source.txt

それでも拡張を行うにはひどい方法です。


確かに、それは悪いコードを含む可能性のあるファイルで「評価」を行うときのリスクです
Ben

0

必要なすべての変数をエクスポートしてから、perlonlinerを使用してください

TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')

これにより、TEXTに存在するすべてのENV変数が実際の値に置き換えられます。引用も保存されます:)


0

すべての非env変数をそのままにして、ソースファイル内のenv変数を置き換えたい場合は、次のコマンドを使用できます。

envsubst "$(printf '${%s} ' $(env | sed 's/=.*//'))" < source.txt > destination.txt

ここでは、特定の変数のみを置き換えるための構文について説明します。上記のコマンドは、サブシェルを使用してすべての定義済み変数を一覧表示し、それをenvsubst

したがって$NAME、と呼ばれる定義済みの環境変数があり、source.txtファイルが次のようになっている場合:

Hello $NAME
Your balance is 123 ($USD)

destination.txtなります:

Hello Arik
Your balance is 123 ($USD)

$NAMEが置き換えられ、$USD手つかずのままになっていることに注意してください


0

単一引用符で-piperlコード()を実行することにより、検索および置換ごとのモード()でperlバイナリを呼び出し-eます。これ%ENVは、エクスポートされた変数名をキーとして、エクスポートされた変数値を次のように含む特別なハッシュのキーを反復処理します。キーの値と反復ごとに、a$<<key>>を含む文字列をその<<value>>。に置き換えるだけです。

 perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' file

警告:2つ以上の変数が同じ文字列で始まる場合は、追加のロジック処理が必要です...


-1

envsubst-v私が使いたかったものとまったく同じように見えますが、オプションは私を少し驚かせました。

envsubst < template.txt正常に動作している間、同じオプション-vが機能していませんでした。

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)
$ envsubst -V
envsubst (GNU gettext-runtime) 0.18.2
Copyright (C) 2003-2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Bruno Haible.

私が書いたように、これは機能していませんでした:

$ envsubst -v < template.txt
envsubst: missing arguments
$ cat template.txt | envsubst -v
envsubst: missing arguments

私はそれを機能させるためにこれをしなければなりませんでした:

TEXT=`cat template.txt`; envsubst -v "$TEXT"

多分それは誰かを助けます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.