Lambdaカクテル

京都在住Webエンジニアの日記です

シェルスクリプトで環境変数の中身を壊すことなくファイルに保存する

★追記があります。

クラウド時代なので,JSONを環境変数に入れて渡したいということがあると思います。そしてそれをファイルに保存したいということがあると思います。

こういうJSONがあるとします。

$ FOO='{"foo":"b\na\nr"}'

アプリケーションの都合でFOOをファイルに保存しないといけない!あなたはちゃんとできますか?

$  echo $FOO > foo.txt
$ cat foo.txt
{"foo":"b
a
r"}

〜完〜: あなたはJSONのパースに失敗する。

おさらい

  • シェルは変数のスペースを展開してくれる
    • FOO="a b c"のとき・・・
    • "$FOO"と書くとスペースは展開されず1つの引数扱いになる
    • $FOO と書くとスペースが展開され,3つの引数扱いになる

これはまあみんな知ってると思うし,今回の本筋ではないです。

ところで・・・

  • シェルはエスケープシーケンスを展開する

これ困るの?ということがあるとおもいますが,たまに困ります。

  • 具体的にはFirebaseをECSで使う場合!!
  • コンテナに含めたくないのでGCPの鍵JSONがAWS Secret Managerを経由して渡ってくる
  • Firebaseの$GOOGLE_APPLIACTION_CREDENTIALSはファイル名しか受け付けないので,ECS側でいったんファイルに落とすということをする必要がある
  • 鍵の文字列リテラルに\nが入っている!!

こういうのが環境変数に入っていると困るわけです。勝手に\nが展開されてしまう。これはいけない。

perl使う

シェルスクリプトでやるのは諦めてperlを使いました。

perl -e 'print $ENV{JSON_STRING_CONTAINING_ESCAPE_SEQUENCE}' > foo.txt

困ったらperl,覚えておきましょう。

追記

シェルスクリプトで環境変数の中身を壊すことなくファイルに保存する - Lambdaカクテル

「困ったらperl」これはひどい。筆者がechoの動作をよく知らないだけ。この場合はprintfコマンドを使うべき。Perlを使えというなら最初からPerlを語ればよく、わざわざシェルスクリプトに言及することには悪意すら感じる。

2020/01/10 15:07
b.hatena.ne.jp

悪意はありませんが,printf "%s" $FOOでも同じことが可能でした。ご指摘ありがとうございました。perlではシェルによる互換性の問題が起こりにくいことから,自分はよく使っています。