I am running a Dockerfile, but, am encountering a problem when I assign a variable for modifying /etc/fail2ban/jail.local, with its string content-"PRIVATEIP".

Dockerfile generates an error and stops. Because I have no idea about assigning a variable with sed to modify the string content in a specific file.

RUN IP=$(cat /root/ip_variable) | sed -i -r "s/PRIVATEIP/${IP}/g" /etc/fail2ban/jail.local
 ---> Running in 1e78ef4318ab

If there are any alternative methods to handle this please let me know.


Add more explanation for an alternative method as below on 2018/July 11:

I add some command lines on Dockerfile. The purpose is same as before. I alternatively use echo to write a script as below. But, it's weird. Why does the fellow character "/" after "s" on "sed" this command get missed? (If there are any methods to add high light or mark on the character within the output of the code, I thanks to you.) If this matter is resolved, I thinks I am able to close this issues.

Step 64/73 : RUN echo "#!/bin/bash\nexport PRIVATEIP=$(cat /home/ip_variable)\nsed -i -r \"s/\bPRIVATEIP\b/\${PRIVATEIP}/g\" /etc/fail2ban/jail.local\nsed -i -r \"s/\bPRIVATEIP\b/\${PRIVATEIP}/g\" /etc/opendkim/TrustedHosts" > /home/start_script.sh
 ---> Running in bbff59f82475
Removing intermediate container bbff59f82475
 ---> 0068d9d600ff
Step 65/73 : RUN cat /home/ip_variable
 ---> Running in faeb4bb1a6ba
Removing intermediate container faeb4bb1a6ba
 ---> f6cc35fd01e5
Step 66/73 : RUN cat /home/start_script.sh
 ---> Running in 95a5ef3b7d23
sed -i -r "sPRIVATEI/${PRIVATEIP}/g" /etc/fail2ban/jail.local
sed -i -r "sPRIVATEI/${PRIVATEIP}/g" /etc/opendkim/TrustedHosts
Removing intermediate container 95a5ef3b7d23
 ---> 6720e7c01efc
Step 67/73 : RUN chmod 755 /home/start_script.sh
 ---> Running in d8ab5e04a846
Removing intermediate container d8ab5e04a846
 ---> decb9e147db9
Step 68/73 : RUN sh /home/start_script.sh
 ---> Running in fc86000f9a2f
sed: -e expression #1, char 28: unknown option to `s'
sed: -e expression #1, char 28: unknown option to `s'
The command '/bin/sh -c sh /home/start_script.sh' returned a non-zero code: 1
  • Can you please share your Dockerfile? – slm Jul 9 '18 at 3:40
  • a wild guess, probably you should use ; instead of | – Siva Jul 9 '18 at 4:51

This works for me:

FROM alpine

COPY ipaddr /ipaddr
COPY ipconf /ipconf
RUN export IPADDR=$(cat /ipaddr) ; sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
CMD cat /ipconf

With ipconf & ipaddr

IP address is IPADDR


>docker build -t dynchange .
Sending build context to Docker daemon   5.12kB
Step 1/5 : FROM alpine
---> 3fd9065eaf02
Step 2/5 : COPY ipaddr /ipaddr
---> Using cache
---> 1828c3157d41
Step 3/5 : COPY ipconf /ipconf
---> 4f43e88e4425
Step 4/5 : RUN export IPADDR=$(cat /ipaddr) ;  sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
---> Running in 722c3d3d9d9e
Removing intermediate container 722c3d3d9d9e
---> 32e31198b70a
Step 5/5 : CMD cat /ipconf
---> Running in 72ea59543a7f
Removing intermediate container 72ea59543a7f
---> 73f8a50d650a
Successfully built 73f8a50d650a
Successfully tagged dynchange:latest

>docker run --rm dynchange
IP address is

However, this is exactly how I would not do it. A better way is to use a build arg:

FROM alpine

COPY ipconf /ipconf
RUN sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
CMD cat /ipconf


>docker build -t dynchange --build-arg IPADDR=  .
Sending build context to Docker daemon   5.12kB
Step 1/5 : FROM alpine
---> 3fd9065eaf02
Step 2/5 : COPY ipconf /ipconf
---> Using cache
---> f5ac88ee48d5
Step 3/5 : ARG IPADDR
---> Running in 58d972e14660
Removing intermediate container 58d972e14660
---> fc3de48160c6
Step 4/5 : RUN sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
---> Running in 8ec855697510
Removing intermediate container 8ec855697510
---> 67e946559316
Step 5/5 : CMD cat /ipconf
---> Running in a5260c593c02
Removing intermediate container a5260c593c02
---> 567a31a517d1
Successfully built 567a31a517d1
Successfully tagged dynchange:latest

>docker run --rm dynchange
IP address is

However I'm not even sure this is the right solution. I would either:

  • build the configuration file outside of the container, and create/replace it with a COPY. This gives full control on its contents.
  • pass that IP address as a parameter when the container is run (environment variable or else), so you have one single container image that can be used in several environments. The CMD orENTRYPOINT can be script that patches the file before calling the main command. You can also pass the configuration file as a VOLUME (this can avoid issues if CMD is run as an application user and patching the config requires root privileges).

Thanks all. I the matter is on delimiter. I change "/" to be ":" and get it worked. I post the result in here. In "Step 65/78", I print the script content and "Step 67/78" run the script well. Thanks @xenoid and @Kusalananda.

Step 63/78 : RUN echo "#!/bin/sh -x\nsed -i 's:PRIVATEIP:'"$(cat /home/ip_variable)"':g' /etc/fail2ban/jail.local\nsed -i 's:PRIVATEIP:'"$(cat /home/ip_variable)"':g' /etc/opendkim/TrustedHosts" > /home/ip_change_script.sh
 ---> Running in 251d6741c37e
Removing intermediate container 251d6741c37e
 ---> 95c4aa62d74a
Step 64/78 : RUN cat /home/ip_variable
 ---> Running in 8825ef517fb8
Removing intermediate container 8825ef517fb8
 ---> 39672eb7021d
Step 65/78 : RUN cat /home/ip_change_script.sh
 ---> Running in 2161051ee4cf
#!/bin/sh -x
sed -i 's:PRIVATEIP:'':g' /etc/fail2ban/jail.local
sed -i 's:PRIVATEIP:'':g' /etc/opendkim/TrustedHosts
Removing intermediate container 2161051ee4cf
 ---> 407ccc7106f7
Step 66/78 : RUN chmod 755 /home/ip_change_script.sh
 ---> Running in 0f6ca7f78ba8
Removing intermediate container 0f6ca7f78ba8
 ---> 250afb327db0
Step 67/78 : RUN sh /home/ip_change_script.sh
 ---> Running in 4b209e18854b
Removing intermediate container 4b209e18854b
 ---> d45d024e1359
Step 68/78 : RUN touch /home/service_boot.log
 ---> Running in 3548dc45f466
Removing intermediate container 3548dc45f466
 ---> 587527e18ab2
Step 69/78 : RUN cat /home/service_boot.log
 ---> Running in b068b00cd584
Removing intermediate container b068b00cd584
 ---> 3183e6b281ed
Step 70/78 : COPY boot_service.sh /home/boot_service.sh
 ---> 9a73dd4fd87d
Step 71/78 : RUN chmod 755 /home/boot_service.sh
 ---> Running in 2f226574e28d
Removing intermediate container 2f226574e28d
 ---> 8a0c14218e1b
Step 72/78 : RUN cat /home/boot_service.sh
 ---> Running in 5fa64827b6dd
  • Funny, : or ~ didn't work for me but | worked fine. – Jujhar Singh Dec 5 '20 at 15:58

An assignment does not produce output and it's therefore pointless to pipe it to another process.

Instead, use ; to divide the pipeline inte two sequential commands:

IP=$(cat /root/ip_variable); sed -i "s/PRIVATEIP/$IP/g" /etc/fail2ban/jail.local

I'm unfamiliar with Docker and it's RUN command. If it only takes a single command, then use

RUN sh -c 'IP=$(cat /root/ip_variable); sed -i "s/PRIVATEIP/$IP/g" /etc/fail2ban/jail.local'


RUN sed -i "s/PRIVATEIP/$(cat /root/ip_variable)/g" /etc/fail2ban/jail.local
  • Thanks. But, it is not working. I writed the command line like yours. I add the command line to Dockerfile. It is RUN echo "#/bin/bash\nIP=$(cat /root/ip_variable)\ndeclare -x IP=\$IP" > /root/ script.sh and RUN /bin/bash /root/script.sh. But, I also use RUN export to check the result. There isn't any variable set. Why I have to use /bin/bash due to the default as sh not bash. The sh won't run declare. So, I use a script to drive it. – jefferyear Jul 10 '18 at 3:39
  • @jefferyear That's no the command I have in my question. – Kusalananda Jul 11 '18 at 8:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.