Windowsでsedを使って環境変数を利用した置換をする

nginxの設定ファイルを起動時に環境変数の値を使って書き換えたい

nginxのerror_logとaccess_logを1箇所で管理しているログディレクトリのパスで書き換えたいけど手動ではやりたくないです。
nginxの引数で-g "error_log xxx;"とかできるけどaccess_logは出来ないのでテンプレートの設定ファイルを用意してsedで書き換えることにしました。

sed for Windows

gnuwin32.sourceforge.net

書き換え

  • ファイルパスの置換 nginxのerror_log等はパスの区切りをバックスラッシュではなくスラッシュ(/)で記述しますが、環境変数はバックスラッシュ(\)なので置換します。
    ※この時、\/に置換しておかないと後処理のsed/がエスケープされなくてエラーになってしまう!

sed的には以下のように書けばよいのですが、

> echo %LOG_HOME%
C:\logs
> echo %LOG_HOME% | sed "s/\\/\\\//g"
C:/logs

バッチファイルの中で使うには変数に代入とか簡単にできないので以下のようにします。

> FOR /F "usebackq" %x IN (`echo %LOG_HOME% ^| sed -e "s/\\/\\\//g"`) DO SET LOG_HOME_NGINX=%x
> echo %LOG_HOME_NGINX
C:/logs

最終的にバッチファイルに記述するときは%x%%xに書き換えてください。

sedの中でパイプを使いたい時にハット(^|)が付いていますがこれがないと以下のようなエラーになります。

| の使い方が誤っています。

わからんて・・・。
ちなみにsedへのパスが通ってない時にも同じエラーになりました。(ますますわからん・・・

  • sedの中で環境変数を展開する sedで、テンプレートに書いてある環境変数のようなキーワードを環境変数で置換するには以下のようにします。
    テンプレートには、error_log %LOG_HOME%/nginx/error.logと定義してあります。
> sed "s/\%%LOG_HOME\%%/%LOG_HOME_NGINX%/" conf\nginx.conf

置換するキーワードはエスケープして、実際の環境変数はエスケープしません。
Windowsならではですが、%を使うために\%%としている所に注意。sed的には\でエスケープだがWindows的には%%と市内と行けないのでダブルで指定している。

  • テンプレートをコピーしてsedで書き換える一連の流れは以下のようになります。
set APP_HOME=%~dp0
copy /Y %APP_HOME%conf\nginx.template %APP_HOME%conf\nginx.conf
FOR /F "usebackq" %%x IN (`echo %LOG_HOME% ^| sed "s/\\/\//"`) DO SET LOG_HOME_NGINX=%%x
sed -i -e "s/\%LOG_HOME\%/%LOG_HOME_NGINX%/" %APP_HOME%conf\nginx.conf
%APP_HOME%nginx.exe -p %APP_HOME% -c %APP_HOME%conf\nginx.conf

Linuxbash使ってとかだと簡単なことが結構つまづいたので記録に残しておきます。