24

I want to output the following text in a Dockerfile:

  *****first row *****  
  *****second row *****    

One way is to do it like that:

cat > Dockerfile <<EOF
FROM alpine:latest
RUN echo '  *****first row *****  ' >> /home/myfile
RUN echo '  *****second row *****  ' >> /home/myfile
ENTRYPOINT cat /home/myfile; sh;
WORKDIR /home
EOF  

But if I have 100 lines it takes time because it runs each command separately and make it as a layer.

Other way is like that:

FROM alpine:latest
RUN printf '  *****first row *****  \n  *****second row *****  \n' >> /home/myfile
ENTRYPOINT cat /home/myfile; sh;
WORKDIR /home

but I don't like it because it make it less readable, especially when you have 100 lines.

I wonder is there a way to do something like that:

FROM alpine:latest
RUN echo '  *****first row *****  
            *****second row *****  ' >> /home/myfile
ENTRYPOINT cat /home/myfile; sh;
WORKDIR /home

Or is there a way to use the ARG command to do it ?

sirlanceoflompoc
  • 941
  • 9
  • 11
E235
  • 11,560
  • 24
  • 91
  • 141

2 Answers2

56

There is another question similar to this with a solution: How to write commands with multiple lines in Dockerfile while preserving the new lines?

The answer to this question is more particular in how to use multiline strings in bash rather than how to use Docker.

Following this solution you may accomplish what you want to do as shown below:

RUN echo $' \n\
*****first row ***** \n\
*****second row ***** \n\
*****third row ***** ' >> /home/myfile

More info about this leading dollar sign here: How does the leading dollar sign affect single quotes in Bash?

Note that this syntax relies on the run command using /bin/bash, not /bin/sh.

sirlanceoflompoc
  • 941
  • 9
  • 11
  • OMG thanks for this solution. Perfect for generating a .repo file to resolve missing rpm install deps, without having to save it into the repo next to the Dockerfile. Also means the file can be generated based on an ARG or ENV boolean, in case the same Dockefile file needs to be used in different environments (resolving against different .repos) – nickboldt Feb 26 '20 at 16:14
  • 2
    I'm not able to suggest edits (queue is full) so note that the last sentence in this answer specifies what might not be obvious. You (probably?) need to add `SHELL ["/bin/bash", "-c"]` in your Dockerfile prior to running this statement. – aaronsteers Jun 13 '20 at 05:12
10

If you have a moderately-sized file, it's usually easier to store it in a separate file and just COPY it in.

FROM alpine:latest
COPY myfile.txt /
CMD cat /myfile.txt

This extends to ENTRYPOINT and CMD commands too. Rather than write a complex shell command (especially as an ENTRYPOINT), it's usually easier to write a separate shell script. If it was important for your application to print the contents of that file before running the main thing the container does, you could write an entrypoint script like

#!/bin/sh
cat /myfile.txt
exec "$@"

and then the Dockerfile

FROM alpine:latest
COPY myfile.txt entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["???"]

This also gives you a place to modify the file at runtime (say, using sed(1)) before running the main program if its actual contents need to depend on environment variables or other runtime data.

David Maze
  • 130,717
  • 29
  • 175
  • 215