これは、なにをしたくて書いたもの?
時々、Dockerfile内で複数行の文字列を作りたくなる時があるのですが、どうやったらいいのかすぐに忘れるのでメモして
おこうかな、と。
環境
今回の環境は、こちらです。
$ docker version
Client: Docker Engine - Community
Version: 20.10.6
API version: 1.41
Go version: go1.13.15
Git commit: 370c289
Built: Fri Apr 9 22:47:17 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.6
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: 8728dd2
Built: Fri Apr 9 22:45:28 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.4
GitCommit: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
runc:
Version: 1.0.0-rc93
GitCommit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
docker-init:
Version: 0.19.0
GitCommit: de40ad0
結論
試した結果としては、複数行の文字列を書く…とはちょっと違いますが、シェルのグルーピング(Compound Commands)を
使うのがよいでしょう。
Command Grouping (Bash Reference Manual)
bash(1): GNU Bourne-Again SHell - Linux man page
こんな感じです。
RUN { \
echo '文字列1'; \
echo '文字列2'; \
echo '文字列3'; \
}
{}
は、()
にしてもOKです。
RUN ( \
echo '文字列1'; \
echo '文字列2'; \
echo '文字列3'; \
)
echoを繰り返しているだけでは?と思うかもですが、コマンドをグルーピングするとリダイレクトを1回で済ませることが
できます。
RUN { \
echo '文字列1'; \
echo '文字列2'; \
echo '文字列3'; \
} > /tmp/test1
RUN ( \
echo '文字列1'; \
echo '文字列2'; \
echo '文字列3'; \
) > /tmp/test2
他の方法としては、echoコマンドの-n
オプションを使って以下のように書けばよいみたいです(dash)。Ubuntu Linuxなど。
RUN echo -n "文字列1\n\
文字列2\n\
文字列3\n"
RUN echo -n '文字列1\n\
文字列2\n\
文字列3\n'
もしくは、こちら(bash、ash)。CentOSやAlpine Linuxなど。
RUN echo -n $'文字列1\n\
文字列2\n\
文字列3\n'
bashやashの場合は、$
が必要で、クォートは'
(シングルクォート)である必要があります。"
(ダブルクォート)ではうまく
いきません。
echoの-n
オプションは、\n
のような\
の部分をエスケープとして解釈してくれるようになります。
enable interpretation of backslash escapes
echo(1): line of text - Linux man page
If -e is in effect, the following sequences are recognized:
\\
backslash
\a
alert (BEL)
\b
backspace
\c
produce no further output
\e
escape
\f
form feed
\n
new line
\r
carriage return
\t
horizontal tab
\v
vertical tab
\0NNN
byte with octal value NNN (1 to 3 digits)
\xHH
byte with hexadecimal value HH (1 to 2 digits)
-n
の有無で、こういう差が出ます。
$ echo '\n'
\n
$ echo -e '\n'
つまり、\n\
で改行と継続行です。
ちなみに、クォートの閉じの前を\
にするとエラーになります。
RUN echo -n "文字列1\n\
文字列2\n\
文字列3\n\"
/bin/sh: 1: Syntax error: Unterminated quoted string
最後の\
を削除するか、以下のように改行を加えましょう。
RUN echo -n "文字列1\n\
文字列2\n\
文字列3\n\
"
お題
複数行の文字列、ということで。今回は以下の内容を複数行の文字列で記述して、/root/.bashrc
に追記するということを
やってみます。
alias helloworld="echo 'Hello World!!'"
alias greeting="echo 'Welcome!!'"
### もしくは
alias helloworld='echo "Hello World!!"'
alias greeting='echo "Welcome!!"'
グルーピング(Compound Commands)を使った例
最初に、結果を。ここに書いたものをecho -n
で試行錯誤するのが、後ろに続きます。
RUN { \
echo ''; \
echo "alias helloworld='echo "'"'"Hello World!!"'"'"'"; \
echo "alias greeting='echo "'"'"Welcome!!"'"'"'" ; \
echo; \
} >> /root/.bashrc
変数展開を使った例。
ARG message1='Hello World!!'
ARG message2='Welcome!!'
RUN { \
echo ''; \
echo "alias helloworld='echo "'"'"${message1}"'"'"'"; \
echo "alias greeting='echo "'"'"${message2}"'"'"'" ; \
echo; \
} >> /root/.bashrc
結果は、どちらも以下になります。
# tail -n 6 /root/.bashrc
# . /etc/bash_completion
#fi
alias helloworld='echo "Hello World!!"'
alias greeting='echo "Welcome!!"'
Ubuntu Linux 20.04 LTS、CentOS 8、Alpine Linux 3.13(.bashrc
はないですが)のいずれでも同じことができます。
このあとは、echo -n
を使って頑張ることに興味がある人は読んでみてください。
Ubuntu Linux 20.04 LTSのイメージを使って、いろんなバリエーションでやってみましょう。
Dockerfile
FROM ubuntu:20.04
RUN echo -n '\n\
alias helloworld="echo '"'"'Hello World!!'"'"'"\n\
alias greeting="echo '"'"'Welcome!!'"'"'"\n\
\n\
' >> /root/.bashrc
いろいろくっついていますが、'
で文字列を開始した中に'
を入れようと頑張っているだけです。
alias helloworld="echo '"'"'Hello World!!'"'"'"\n\
alias greeting="echo '"'"'Welcome!!'"'"'"\n\
Dockerイメージをビルド。
$ docker image build -t kazuhira/ubuntu:20.04 .
実行。
$ docker container run -it --rm kazuhira/ubuntu:20.04
root@710cc3521c1a:/#
確認。
# tail -n 6 /root/.bashrc
# . /etc/bash_completion
#fi
alias helloworld="echo 'Hello World!!'"
alias greeting="echo 'Welcome!!'"
OKですね。
# helloworld
Hello World!!
# greeting
Welcome!!
クォートを"
にしてみます。
RUN echo -n "\n\
alias helloworld='echo "'"'"Hello World!!"'"'"'\n\
alias greeting='echo "'"'"Welcome!!"'"'"'\n\
\n\
" >> /root/.bashrc
確認。
# tail -n 6 /root/.bashrc
# . /etc/bash_completion
#fi
alias helloworld='echo "Hello World!!"'
alias greeting='echo "Welcome!!"'
alias
を使った実行結果は同じなので、省略。
'
と"
の差は想像に難くないですが、変数展開ですね。
FROM ubuntu:20.04
ARG message1='Hello World!!'
ARG message2='Welcome!!'
RUN echo -n '\n\
alias helloworld="echo ${message1}"\n\
alias greeting="echo ${message2}"\n\
\n\
' >> /root/.bashrc
RUN echo -n "\n\
alias helloworld='echo ${message1}'\n\
alias greeting='echo ${message2}'\n\
\n\
" >> /root/.bashrc
結果。
# tail -n 10 /root/.bashrc
# . /etc/bash_completion
#fi
alias helloworld="echo ${message1}"
alias greeting="echo ${message2}"
alias helloworld='echo Hello World!!'
alias greeting='echo Welcome!!'
続いて、CentOS 8で試してみましょう。
Dockerfile
FROM centos:8.3.2011
RUN echo -n $'\n\
alias helloworld="echo Hello World!!"\n\
alias greeting="echo Welcome!!"\n\
\n\
' >> /root/.bashrc
Ubuntu Linuxの時のように、'
の中に'
を含めるのはちょっとムリそうでした…。
Dockerイメージのビルド。
$ docker image build -t kazuhira/centos:8.3.2011 .
確認。
# tail -n 6 /root/.bashrc
. /etc/bashrc
fi
alias helloworld="echo Hello World!!"
alias greeting="echo Welcome!!"
aliasの実行結果は割愛します。
クォートが'
しか使えないので、変数を含めた場合は
FROM centos:8.3.2011
ARG message1='Hello World!!'
ARG message2='Welcome!!'
RUN echo -n $'\n\
alias helloworld="echo ${message1}"\n\
alias greeting="echo ${message2}"\n\
\n\
' >> /root/.bashrc
展開されずにそのまま残ってしまいます。
# tail -n 6 /root/.bashrc
. /etc/bashrc
fi
alias helloworld="echo ${message1}"
alias greeting="echo ${message2}"
最後は、Alpine Linux 3.13。Alpine Linuxには.bashrc
がないので、適当にファイルに出力して確認。
Dockerfile
FROM alpine:3.13.5
ARG message1='Hello World!!'
ARG message2='Welcome!!'
RUN echo -n $'\n\
alias helloworld="echo Hello World!!"\n\
alias greeting="echo Welcome!!"\n\
\n\
' >> /tmp/test
RUN echo -n $'\n\
alias helloworld="echo ${message1}"\n\
alias greeting="echo ${message2}"\n\
\n\
' >> /tmp/test
ビルド。
$ docker image build -t kazuhira/alpine:3.13.5 .
確認。
$ docker container run -it --rm kazuhira/alpine:3.13.5 cat /tmp/test
alias helloworld="echo Hello World!!"
alias greeting="echo Welcome!!"
alias helloworld="echo ${message1}"
alias greeting="echo ${message2}"
CentOS 8と同じですね。
とまあ、echo -n
を使って頑張って複数行の文字列にした割には、グルーピング(Compound Commands)に比べると
報われないので。
素直にいきましょう。