mpen
mpen

Reputation: 283325

Docker run bash --init-file

I'm trying to create an alias to help debug my docker containers.

I discovered bash accepts a --init-file option which ought to let us run some commands before passing over to interactive mode.

So I thought I could do

docker-bash() {
  docker run --rm -it "$1" bash --init-file <(echo "ls; pwd")
}

But those commands don't appear to be running:

 % docker-bash c7460dfcab50
root@9c6f64a9db8c:/#

Is it an escaping issue or.. what's going on?

bash --init-file <(echo "ls; pwd")

Alone in a terminal on my host machine works as expected (runs the command starts a new bash instance).

Upvotes: 2

Views: 3019

Answers (2)

KamilCuk
KamilCuk

Reputation: 141930

In points:

  • The <(...) is a bash extension process subtitution.
  • From the manual above: Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files..
  • The process substitution works like this:
    • bash creates a fifo in /tmp or creates a new file descriptor in /dev/fd.
    • The filename, either the /tmp/.something or /dev/fd/<number> is substituted for <(...) when command is executed.
    • So for example echo <(echo 1) outputs /dev/fd/63.
  • Docker works by creating a new environment that is separated from the host. That means that:
    • Processes inside docker do not inherit file descriptors from the host process:
      • So /dev/fd/* files are not inherited.
    • Processes inside docker are accessing isolated filesystem tree.
      • So processes can't access /tmp/* files from the host.
  • So summarizing docker run -ti --rm alpine cat <(echo 1) will not work, because the filename substituted by <(...) is not available from docker environment.

An easy workaround would be to just:

docker run -ti --rm alpine sh -c 'ls; pwd; exec sh'

Or use a temporary file:

echo "ls; pwd" > /tmp/tempfile
docker run -v /tmp/tempfile:/tmp/tempfile bash bash --init-file /tmp/tempfile

Upvotes: 5

mpen
mpen

Reputation: 283325

For my use-case I wanted to set an alias which won't persist if we re-exec the shell. However, aliases can be written to ~/.bashrc which will be reloaded on the subsequent exec. Ergo,

docker-bash() {
  docker run --rm -it "$1" bash -c $'set -o xtrace; echo "alias ll=\'ls -lAhtrF --color=always\'" >> ~/.bashrc; exec "$0"'
}

Works. --rm should clean up any files we create anyway if I understand properly how docker works.

Or perhaps this is a nicer way to write it:

docker-bash() {
read -r -d '' BASHRC << EOM
alias ll='ls -lAhtrF --color=always'
EOM
docker run --rm -it "$1" bash -c "echo \"$BASHRC\" >> ~/.bashrc; exec \"\$0\""
}

Upvotes: 2

Related Questions