This page has been machine-translated from the original page.
This article explains how to fix a problem where Tab completion does not work for arguments when using make inside a Docker container.
I do my hobby OS development in a Docker container, and I ran into a problem where Tab completion for Makefile arguments did not work inside a container I logged into with the docker run command.
Normally, I wanted Makefile arguments such as make build to be completed with the Tab key as shown in the following image, but it did not work correctly in the shell inside the Docker container I connected to.

Solution
If Makefile Tab completion does not work, install bash-completion with the following command, then load /etc/bash_completion with Bash’s source command.
sudo apt install bash-completion -y
source /etc/bash_completionAfter that, Tab completion became available.
But what is bash-completion in the first place?
According to the README, it seems to be a tool for enhancing Tab completion in the Bash shell.
bash-completion is a collection of command line command completions for the Bash shell, a collection of helper functions to assist in creating new completions, and a set of facilities for loading and installing completions automatically.With bash-completion installed, you can also complete option arguments for standard tools such as systemctl, not just Makefile arguments.
It is extremely convenient.
By the way, after installing bash-completion, you can check whether it is enabled by running the following command and seeing whether it produces a large amount of output.
complete -pThe following article was helpful for more details.
Using bash-completion to hammer out long commands without looking at man pages or help - Qiita
bash-completion does not become active in a Docker container
So, if you add a line to install bash-completion to the Dockerfile and then build the image, it seems like the problem of Tab completion not working should be resolved.
Here I created an image using the following Dockerfile.
# Dokcerfile
FROM python:3.8
ENV PYTHONUNBUFFERED 1
ENV TZ=Asia/Tokyo
RUN mkdir -p /homedir
ENV HOME=/homedir
WORKDIR $HOME
# If you henge shell to Bash
# Shell ["/bin/bash", "-c"]
RUN useradd ubuntu
RUN dpkg --add-architecture i386
RUN apt update && apt upgrade -y
# Utils
RUN apt install vim unzip zip gdb ltrace strace bash-completion -y
# Devtools
RUN apt install mtools nasm build-essential g++ make -y
# Qemu
RUN apt install qemu qemu-system-x86 qemu-utils qemu-system-arm -yHowever, when I logged into the image I created with the following command, Tab completion did not work.
docker run --rm -it -v mydir:/homedir mycontainer /bin/bashIf I ran source /etc/bash_completion inside the logged-in container first, Tab completion worked normally after that, so bash-completion itself seemed to be installed correctly.
Also, under /etc/profile.d, bash_completion.sh was present as shown below.
root@ab80c3738102:~# cat /etc/profile.d/bash_completion.sh
# Check for interactive bash and that we haven't already been sourced.
if [ -n "${BASH_VERSION-}" -a -n "${PS1-}" -a -z "${BASH_COMPLETION_VERSINFO-}" ]; then
# Check for recent enough version of bash.
if [ ${BASH_VERSINFO[0]} -gt 4 ] || \
[ ${BASH_VERSINFO[0]} -eq 4 -a ${BASH_VERSINFO[1]} -ge 1 ]; then
[ -r "${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion" ] && \
. "${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion"
if shopt -q progcomp && [ -r /usr/share/bash-completion/bash_completion ]; then
# Source completion code.
. /usr/share/bash-completion/bash_completion
fi
fi
fiBecause of that, it seems that the cause was /etc/profile.d/bash_completion, which should normally be loaded by /etc/profile when the shell starts, was not being loaded when I logged in with the method above.
When I checked the documentation for the docker run command, I found the following description.
The
docker runcommand first creates a writable container layer on top of the specified image, then starts it using the specified command.In other words,
docker runis equivalent to the API endpoints/containers/createand/containers/(id)/start. A stopped container can be restarted with all previous changes preserved by usingdocker start.See
docker ps -ato list all containers.
In other words, calling /bin/bash with the docker run -it command means starting an interactive Bash process inside the launched Docker container and connecting the caller’s standard input and output to it through a pseudo-TTY.
The cause of the problem here was that bash_completion, which should be loaded by /etc/profile when the Docker container starts (that is, when connecting to the Bash process launched by docker run), was not being loaded.
And that makes sense, because /etc/profile is only loaded when logging in to a shell.
So if you only start Bash with the run command, it will not be loaded in the first place.
Once I had identified the cause, I changed the Docker container startup command as follows.
docker run --rm -it -v mydir:/homedir mycontainer /bin/bash -login
This -login option tells Bash to intentionally load environment settings such as profile before running.
By connecting to a container started with this command, Tab completion started working properly.
Summary
I started writing this article as a quick memo, but it ended up deepening my understanding of Bash Tab completion, Docker commands, and how the Bash shell works, so it was very educational.