Using the RUN instruction in a Dockerfile with 'source' does not work

bash, docker, shell

Solution

Original Answer

FROM ubuntu:14.04
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

This should work for every Ubuntu docker base image. I generally add this line for every Dockerfile I write.

Edit by a concerned bystander

If you want to get the effect of "use `bash` instead of `sh` throughout this entire Dockerfile", without altering and possibly damaging* the OS inside the container, you can just tell Docker your intention. That is done like so:

SHELL ["/bin/bash", "-c"]

* The possible damage is that many scripts in Linux (on a fresh Ubuntu install `grep -rHInE '/bin/sh' /` returns over 2700 results) expect a fully POSIX shell at `/bin/sh`. The bash shell isn't just POSIX plus extra builtins. There are builtins (and more) that behave entirely different than those in POSIX. I FULLY support avoiding POSIX (and the fallacy that any script that you didn't test on another shell is going to work because you think you avoided basmisms) and just using bashism. But you do that with a proper shebang in your script. Not by pulling the POSIX shell out from under the entire OS. (Unless you have time to verify all 2700 plus scripts that come with Linux plus all those in any packages you install.)

More detail in this answer below. https://stackoverflow.com/a/45087082/117471

Problem

I have a Dockerfile that I am putting together to install a vanilla python environment (into which I will be installing an app, but at a later date). ``` FROM ubuntu:12.04 # required to build certain python libraries RUN apt-get install python-dev -y # install pip - canonical installation instructions from pip-installer.org # http://www.pip-installer.org/en/latest/installing.html ADD https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py /tmp/ez_setup.py ADD https://raw.github.com/pypa/pip/master/contrib/get-pip.py /tmp/get-pip.py RUN python /tmp/ez_setup.py RUN python /tmp/get-pip.py RUN pip install --upgrade pip # install and configure virtualenv RUN pip install virtualenv RUN pip install virtualenvwrapper ENV WORKON_HOME ~/.virtualenvs RUN mkdir -p $WORKON_HOME RUN source /usr/local/bin/virtualenvwrapper.sh ``` The build runs ok until the last line, where I get the following exception: ``` [previous steps 1-9 removed for clarity] ... Successfully installed virtualenvwrapper virtualenv-clone stevedore Cleaning up... ---> 1fc253a8f860 Step 10 : ENV WORKON_HOME ~/.virtualenvs ---> Running in 8b0145d2c80d ---> 0f91a5d96013 Step 11 : RUN mkdir -p $WORKON_HOME ---> Running in 9d2552712ddf ---> 3a87364c7b45 Step 12 : RUN source /usr/local/bin/virtualenvwrapper.sh ---> Running in c13a187261ec /bin/sh: 1: source: not found ``` If I `ls` into that directory (just to test that the previous steps were committed) I can see that the files exist as expected: ``` $ docker run 3a87 ls /usr/local/bin easy_install easy_install-2.7 pip pip-2.7 virtualenv virtualenv-2.7 virtualenv-clone virtualenvwrapper.sh virtualenvwrapper_lazy.sh ``` If I try just running the `source` command I get the same 'not found' error as above. If I RUN an interactive shell session however, source does work: ``` $ docker run 3a87 bash source bash: line 1: source: filename argument required source: usage: source filename [arguments] ``` I can run the script from here, and then happily access `workon`, `mkvirtualenv` etc. I've done some digging, and initially it looked as if the problem might lie in the difference between bash as the Ubuntu login shell, and dash as the Ubuntu system shell, dash not supporting the `source` command. However, the answer to this appears to be to use '.' instead of `source`, but this just causes the Docker runtime to blow up with a go panic exception. What is the best way to run a shell script from a Dockerfile RUN instruction to get around this (am running off the default base image for Ubuntu 12.04 LTS).

Original source