admin管理员组文章数量:1312693
My ENV
variable in the Dockerfile
requires a newline sequence (\n
). Using the ENV
instruction, it seems impossible to achieve this.
I've tried all possible combinations, I think:
# Dockerfile
ENV FOO @static {\n path_regexp \\n} # @static {n path_regexp \\n}
ENV BAR='@static {\n path_regexp \n}' # @static {\\n path_regexp \\n}
ENV BAZ="@static {\n path_regexp \n}" # @static {\\n path_regexp \\n}
\n
is always prepended with a backslash. Is this a "feature"? How can I make my ENV
respect the newline sequence?
Putting the variabile directly in Compose file will output the variabile correctly.
My ENV
variable in the Dockerfile
requires a newline sequence (\n
). Using the ENV
instruction, it seems impossible to achieve this.
I've tried all possible combinations, I think:
# Dockerfile
ENV FOO @static {\n path_regexp \\n} # @static {n path_regexp \\n}
ENV BAR='@static {\n path_regexp \n}' # @static {\\n path_regexp \\n}
ENV BAZ="@static {\n path_regexp \n}" # @static {\\n path_regexp \\n}
\n
is always prepended with a backslash. Is this a "feature"? How can I make my ENV
respect the newline sequence?
Putting the variabile directly in Compose file will output the variabile correctly.
Share Improve this question asked Feb 1 at 16:46 gremogremo 48.5k80 gold badges271 silver badges447 bronze badges 4 |5 Answers
Reset to default 3Docker doesn't replace escaped characters in the ENV statement.
You can replace them at runtime by echoing them into new variables as this shows
FROM debian
ENV foo="Hello\nWorld!"
CMD bar=$(echo ${foo}) && echo ${#foo} && echo ${#bar}
It prints 13 and 12 showing that foo
is 13 characters long and bar
is 12 long, so \n
has been replaced with a newline.
I don't believe you can do this with only a Dockerfile. The parsing on the ENV
step is very minimal. However, you can define the variable outside of the build, and pass it in as a build arg:
$ cat df.env
from alpine
arg hello
env hello=${hello}
cmd env
$ hello="hello
> world"
$ docker build -t test-env -f df.env --build-arg "hello=$hello" .
[+] Building 0.2s (5/5) FINISHED docker:default
=> [internal] load build definition from df.env 0.0s
=> => transferring dockerfile: 84B 0.0s
=> WARN: JSONArgsRecommended: JSON arguments recommended for cmd to prevent unintended behavior r 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 49B 0.0s
=> CACHED [1/1] FROM docker.io/library/alpine:latest 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:11ff645049d1b266b68f2b0fe1da19ef0daccaf103bbafc2030b10d58eb0d6b6 0.0s
=> => naming to docker.io/library/test-env 0.0s
1 warning found (use docker --debug to expand):
- JSONArgsRecommended: JSON arguments recommended for cmd to prevent unintended behavior related to OS signals (line 5)
$ docker run --rm test-env
HOSTNAME=af8f8744374d
SHLVL=1
HOME=/root
hello=hello
world
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
Another option to do this is to expand the variable inside of an entrypoint script, in this case using printf
. This will only apply to child processes of the entrypoint, so a docker exec
would see the unexpanded variable:
from alpine
env hello=hello\\nworld
copy --chmod=755 <<-"EOT" /entrypoint.sh
#!/bin/sh
export hello="$(printf "$hello")"
if [ $# = 0 ]; then
set -- /bin/sh
fi
exec "$@"
EOT
entrypoint [ "/entrypoint.sh" ]
cmd env
Multiline ENV variables in a Dockerfile
Docker will always automatically escape literal \n
in a Dockerfile ENV
instruction. Therefore you need some workaround
a) e.g. unescaping on startup:
# Define ENV variable (Docker escapes \n to \\n)
ENV FOO="@static {\n path_regexp \n}"
# unescape just-in-time using printf %b
CMD ["/bin/sh", "-c", "export FOO=$(printf '%b' \"$FOO\") && exec your_application"]
b) you could create a docker ENTRYPOINT
script manually with the varible(s) defined there (probably the cleanest way)
ENTRYPOINT ["/entrypoint.sh"]
CMD ["your_application"]
c) in case you don't want to change or mess with a potentially inherited ENTRYPOINT - you could dynamically create a startup script:
# Create a startup script that contains the vars
RUN cat << 'EOF' > /startup.sh
#!/bin/sh
export FOO="@static {\n path_regexp \n}"
exec "$@"
EOF
RUN chmod +x /startup.sh
CMD ["/bin/sh", "-c", "source /startup.sh && exec your_application"]
Answer to your first statement:
"Using the ENV instruction, it seems impossible to achieve this."
Yes, because Docker’s ENV instruction sets variables as single-line strings and treats \n literally instead of as a newline (0x0A).
Since Docker Compose works (it supports multi-line YAML), you can alternatively use a shell command in the Dockerfile:
Dockerfile
➜ Documents cat Dockerfile
FROM debian
ENV FOO="@static {\\n path_regexp \\n}"
RUN echo 'export FOO=$(echo -e "$FOO")' >> /root/.bashrc
CMD ["/bin/bash"]
This interprets \n as a newline.
➜ Documents docker run -it test-newline /bin/bash
root@1ef320838ff3:/# env
HOSTNAME=1ef320838ff3
PWD=/
FOO=@static {
path_regexp
}
HOME=/root
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env
root@1ef320838ff3:/# exit
Hope that solves it!
New lines are not escaped, probably the tests that you are using is printing the output in some other format. Here are two examples that you can try:
FROM alpine
ENV FOO="Hello\nWorld!"
CMD ["sh", "-c", "echo -e ${FOO}"]
and
FROM alpine
ENV FOO='echo -e "Hello\nWorld!"'
CMD ["sh", "-c", "$FOO"]
本文标签:
版权声明:本文标题:docker - Literal "n" in Dockerfile ENV instruction: is this literally impossible to achieve? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741870080a2402141.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
env
in the container you'll see the variables are all as you expect – Paolo Commented Feb 3 at 8:55