1. ホーム
  2. bash

[解決済み] Bash Templating。Bashでテンプレートから設定ファイルを作るには?

2022-04-26 01:23:06

質問

自分のウェブサーバー用に、ApacheとPHPの設定ファイルを自動作成するスクリプトを書いています。CPanelやISPConfigのようなGUIは使いたくありません。

私は、ApacheとPHPの設定ファイルのいくつかのテンプレートを持っています。Bashスクリプトは、テンプレートを読み、変数の置換を行い、解析されたテンプレートをいくつかのフォルダに出力する必要があります。それを行うための最良の方法は何ですか?私はいくつかの方法を考えることができます。どれがベストですか、またはそれを行うにはいくつかのより良い方法があるかもしれませんか?私は純粋なBashでそれをしたいです(例えばPHPでは簡単です)。

1) テキストファイルの${}プレースホルダーを置換する方法は?

template.txtを使用します。

the number is ${i}
the word is ${word}

script.shを使用します。

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

ところで、ここで出力を外部ファイルにリダイレクトするにはどうしたらいいのでしょうか?変数に引用符などが含まれている場合、何かエスケープする必要があるのでしょうか?

2) cat & sed を使って、各変数をその値に置き換える。

与えられたtemplate.txt。

The number is ${i}
The word is ${word}

コマンドです。

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

多くのシンボルをエスケープする必要があり、また多くの変数を使用すると行が長くなりすぎるため、私には悪いように思えます。

他にエレガントで安全な解決策はないのでしょうか?

どのように解決するのですか?

これを使うことができます。

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < template.txt

をすべて置き換えるために ${...} の文字列を、対応する環境変数に置き換えてください(このスクリプトを実行する前に、環境変数をエクスポートすることを忘れないでください)。

純粋なbashの場合、これは動作するはずです(変数に${...}文字列が含まれないと仮定しています)。

#!/bin/bash
while read -r line ; do
    while [[ "$line" =~ (\$\{[a-zA-Z_][a-zA-Z_0-9]*\}) ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo "$line"
done

. RHSが自分自身を参照する変数を参照してもハングしない解決策。

#!/bin/bash
line="$(cat; echo -n a)"
end_offset=${#line}
while [[ "${line:0:$end_offset}" =~ (.*)(\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})(.*) ]] ; do
    PRE="${BASH_REMATCH[1]}"
    POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
    VARNAME="${BASH_REMATCH[3]}"
    eval 'VARVAL="$'$VARNAME'"'
    line="$PRE$VARVAL$POST"
    end_offset=${#PRE}
done
echo -n "${line:0:-1}"

警告 : bashでNULを含む入力を正しく処理する方法、あるいは末尾の改行量を保持する方法を知りません。最後のバリエーションは、シェルがバイナリ入力を「愛する」ために、そのまま提示されます。

  1. read はバックスラッシュを解釈します。
  2. read -r はバックスラッシュを解釈しませんが、最終行が改行で終わっていない場合は削除されます。
  3. "$(…)" は末尾の改行を存在する数だけ取り除くので、私は ; echo -n a を使用し echo -n "${line:0:-1}" : これは最後の文字を削除します (これは a を含む)、入力と同じ数の末尾の改行を保持します。