Dockerfileで複数行を改行付きでechoする際にハマったので共有しておきます

2020-12-02Bash,Docker

はじめに

最近Dockerfileを作成したときに、 RUN コマンド内で改行付き情報を echo したかったのですが、多少ハマってしまったので共有します。

「2019-07-17 追記」コメント欄より

コメントを下さった Nig さん、ありがとうございます。勉強になりました。

以下のような構文を利用する際に、シングルクォーテーション( ' )で記述しないといけない部分がダブルクォーテーション( " )になっていたことが原因とのことでした。

*※debian系のLinuxOSを利用している場合、シングルクォーテーションの前の $ を削除しないといけないようです。不要な $ が出力されてしまいました。

FROM centos:centos7

RUN echo $'\n\
alias ll="ls -l"\n\
alias la="ls -a"\n\
alias lla="ls -l -a"\n\
' >> /root/.bashrc

※上記のスタイル以外で記述したい方は、当エントリを読み進めいただく意義はあるかと思います。

検証環境

$ uname -moi
x86_64 MacBookPro11,4 Darwin

$ docker --version
Docker version 18.09.2, build 6247962

経緯(失敗例)

Dockerイメージ作成のために「Dockerfile」を作成しました。

その際に、.bashrcファイルにaliasを追加したかったので、 ネット上に転がっている情報を参考に 以下のように記述しました。

FROM centos:centos7

RUN echo $"\n\
alias ll='ls -l'\n\
alias la='ls -a'\n\
alias lla='ls -l -a'\n\
" >> /root/.bashrc

echo コマンドの引数として渡す情報の各行末に \n\ と記述することで、以下の命令と同等の出力が行われるとのことでした。

$ echo $"
alias ll='ls -l'
alias la='ls -a'
alias lla='ls -l -a'
" >> /root/.bashrc

実際に試してみると...

イメージをビルドし、起動してみます。

# ビルド
$ docker build . --tag=genzouw/test

# 起動
$ docker run --rm -it genzouw/test bash
bash: nalias: command not found
[root@19775d30756e /]#

一応起動はできたのですが、エラーが発生しています。
~/.bashrc を確認してみます。

[root@19775d30756e /]# tail ~/.bashrc

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi
\nalias ll='ls -l'\nalias la='ls -a'\nalias lla='ls -l -a'\n

最終行の alias の内容がめちゃくちゃですね。
うまく改行できていないことがわかります。

echo -e で対処する

「Dockerfile」を以下のように書き換えることで対処できました。

FROM centos:centos7

RUN echo -e "\n\
alias ll='ls -l'\n\
alias la='ls -a'\n\
alias lla='ls -l -a'\n\
" >> /root/.bashrc

ビルドしてイメージを作成後、起動すると今度は問題なく動作しました。

echo -e とは?

マニュアルを引いてみる。

$ man echo

一部抜粋すると以下のように書かれている。

    -e     enable interpretation of backslash escapes

    ...

    If -e is in effect, the following sequences are recognized:

    ...

    \n     new line

-e オプションを付けないと \n を改行として取り扱ってくれないようですね。

他のGithubリポジトリではどうしている?

ちなみに、他のGithubリポジトリではどうしているのか知りたくありませんか?

ためしに WordPress のリポジトリを覗いてみました。

非常に簡潔で、echo コマンドを連発するという方法をとっています。

以下、一部抜粋

...
RUN { \
        echo 'opcache.memory_consumption=128'; \
        echo 'opcache.interned_strings_buffer=8'; \
        echo 'opcache.max_accelerated_files=4000'; \
        echo 'opcache.revalidate_freq=2'; \
        echo 'opcache.fast_shutdown=1'; \
    } > /usr/local/etc/php/conf.d/opcache-recommended.ini
...

{...} のシェル構文でechoコマンドの実行結果をグルーピングし、ファイルにリダイレクト、という方法をとっています。見やすいですね。

ひとこと

環境に依存するのかな?
なぜ他の方々は -e オプション無しで問題が起きてないのか。

2020-12-02Bash,Docker