Exciting news! TCMS official website is live! Offering full-stack software services including enterprise-level custom R&D, App and mini-program development, multi-system integration, AI, blockchain, and embedded development, empowering digital-intelligent transformation across industries. Visit dev.tekin.cn to discuss cooperation!
This article comprehensively summarizes 4 practical methods to write multi-line configurations and scripts to files in a Dockerfile, with a focus on the incompatibility of the syntax=docker/dockerfile:1 heredoc syntax in legacy Docker (v0) versions. Based on locally tested and validated approaches including RUN { ... }|tee, echo $'...', printf, and backslash line continuation ...
Writing multi-line scripts and configuration files directly into containers is a frequent operation in Docker image building. However, many developers encounter common issues: the modern syntax=docker/dockerfile:1 heredoc syntax fails to work in legacy Docker (v0) versions, leading to line break errors, variable exceptions, and permission loss.
This article features locally tested, stable writing methods that do not rely on advanced syntax and are compatible with all Docker versions. It compiles a set of the most practical, secure, and production-ready solutions for multi-line file writing.
Many tutorials recommend the heredoc syntax as follows:
# syntax=docker/dockerfile:1
RUN <<EOF cat > file.sh
...
EOF
This approach has critical drawbacks:
Conclusion: For stability and universal compatibility, traditional RUN syntax is a must—and it is the core focus of this article.
All methods below have been locally tested and validated with no compatibility issues, and can be copied and used directly.
Ideal for complete shell scripts with clear structure, easy maintenance, and no escape character headaches.
RUN { \
echo '#!/bin/sh'; \
echo 'set -eu'; \
echo; \
echo 'if [ -L "/app/sentry/node_modules" ]; then'; \
echo ' rm -f /app/sentry/node_modules'; \
echo 'fi'; \
echo 'ln -s /app/sentry_deps/node_modules /app/sentry/node_modules'; \
echo 'exec "$@"'; \
} | tee /app/entrypoint.sh && chmod +x /app/entrypoint.sh
Advantages:
echo for each line, intuitive and error-resistant.tee outputs content to the console simultaneously for easy debugging.Suitable for small configuration files such as .ini / .conf / .yaml:
RUN echo $'[section]\n\
key=value\n\
another_key=another_value' > /etc/my_config.ini
$'...' natively recognizes \n as line breaks.\ must be at the end of the line with no trailing spaces.Ideal for scenarios requiring strict control over line breaks and spaces:
RUN printf "user=root\n\
pass=123456\n\
host=127.0.0.1\n" > /etc/db.conf
Suitable for writing complete logic scripts in a single block:
RUN echo $'#!/bin/sh\n\
set -eu\n\
if [ -L "/app/sentry/node_modules" ]; then\n\
rm -f /app/sentry/node_modules\n\
fi\n\
exec "$@"' > /entrypoint.sh && chmod +x /entrypoint.sh
\—this will cause immediate build errors.chmod +x to scripts; otherwise, they cannot be executed.echo 'a': output content as-is, no variable interpolation.echo "a$var: enable variable interpolation.> overwrites the target file; >> appends content to the target file.set -eu to multi-line scripts to improve robustness (abort on error/unset variable).-L to check for symbolic links and -d to check for directories.FROM tekintian/alpine:3.12
ENV SENTRY_VERSION="8.26.0" \
NODE_VERSION="8.17.0" \
NODE_ENV=development
LABEL maintainer="tekintian@gmail.com"
LABEL version="${SENTRY_VERSION}"
WORKDIR /app
# Write entrypoint script (compatible with all Docker versions, most stable)
RUN { \
echo '#!/bin/sh'; \
echo 'set -eu'; \
echo; \
echo 'if [ -L "/app/sentry/node_modules" ]; then'; \
echo ' echo "🗑️ Clean up old symlink"'; \
echo ' rm -f /app/sentry/node_modules'; \
echo 'fi'; \
echo; \
echo 'if [ -d "/app/sentry/node_modules" ] && [ ! -L "/app/sentry/node_modules" ]; then'; \
echo ' BACKUP="node_modules_$(date +%Y%m%d%H%M%S)"'; \
echo ' mv /app/sentry/node_modules /app/sentry/$BACKUP'; \
echo 'fi'; \
echo; \
echo 'ln -s /app/sentry_deps/node_modules /app/sentry/node_modules'; \
echo 'echo "✅ Build completed: ${SENTRY_VERSION}"'; \
echo 'exec "$@"'; \
} | tee /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh
# Create directories in advance
RUN mkdir -p /app/sentry /app/sentry_deps/node_modules
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["sleep","infinity"]
RUN { ... } | tee.echo $'...' is the simplest option.#syntax=docker/dockerfile:1 heredoc syntax blindly—it causes severe incompatibility issues.#Docker #DevOps #EnterprisePractice