複数行変数を持つシェルスクリプトで sed を使用する

複数行変数を持つシェルスクリプトで sed を使用する

シェル スクリプトを使用して、さまざまな種類の VM をセットアップします。多くの場合、これらのスクリプトには、 を使用して構成ファイルの特定の位置に挿入する必要がある複数行の変数が含まれていますsed

次のように作成すれば、すべて問題ありません。

VAR="Config Line1\nConfig Line2\nConfig Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile

ただし、テキスト ブロックがかなり長くなる可能性があるため、スクリプトが読みにくくなります。

次のように書くと:

VAR="Config Line1
Config Line2
Config Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile

スクリプトを実行するとエラーが発生します: sed: -e expression #1, char 31: unknown command:C'`

sedこのように宣言された変数を使用する方法はありますか?

答え1

コマンドの標準構文は次のaとおりです。

sed -e 'a\
first line\
  second line\
last line'

BSD(少なくともFreeBSDとOS/X)はsed先頭の空白を削除します、 そして-eバグを回避するためにGNU では、最初の行が空でない限り、sedの直後に移動できます。a\

したがって、入力を前処理する必要があります。

VAR='content with
multiple lines
  some with lead blanks
or even backslash\'

preprocessed_VAR=$(printf '%s\n' "$VAR" |
  sed 's/\\/&&/g;s/^[[:blank:]]/\\&/;s/$/\\/')

sed -i -e "/MatchingPattern/a\\
${preprocessed_VAR%?}" somefile

( FreeBSD または OS/X では-iに置き換えてください-i '')。

GNU/Linux および GNU シェル ( bash) またはを使用する場合はzsh、代わりに次のように実行できます。

sed -i '/MatchingPattern/r /dev/stdin' <<< "$VAR"

これが機能するのはbashzsh削除された一時ファイルを使用して here-strings を実装し、Linux 上の /dev/stdin がファイルへのシンボリック リンクとして実装されているためです (つまり、複数回開くことができ、そのたびに先頭で開きます)。

ここでは、代わりに GNU を使用することもできますawk

(export VAR
gawk -i /usr/share/awk/inplace.awk '{print}; /MatchingPattern/{print ENVIRON["VAR"]}' somefile)

使ってはいけません-i inplaceは、まず現在の作業ディレクトリから拡張機能(または)gawkをロードしようとしますが、そこに誰かがマルウェアを仕掛けている可能性があります。で提供される拡張機能のパスはシステムによって異なる場合があります。inplaceinplaceinplace.awkinplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

またはperl(その-i由来は):

(export VAR
perl -pi -e '$_ .= "$ENV{VAR}\n" if /MatchingPattern/' somefile)

答え2

sedこのエラーは、 append コマンドaで実際の の後にバックスラッシュが必要であるために発生しますa

GNUの場合sed:

$ sed "/pattern/a\\$VAR" file.in >file.out

sed私の知る限り、BSDでは、a改行が適切にエスケープされていない限り、コマンドを使用してファイルに 1 行しか挿入できません。

BSD でこれを解決する方法に関する関連した回答sed:http://unix.stackexchange.com/a/60322

関連情報