Speed up your Docker workflow with Bash functions
Tags: docker, bash, linux, webdev
Published: 2020-11-02 20:24:42

[This article is also available on Medium.](https://danielgaldev.medium.com/speed-up-your-docker-workflow-with-bash-functions-45f522bd87a4)
# Introduction

I am a web developer and I use docker-compose in all of my projects. Sometimes it is just one container for the frontend part of the app, sometimes it is the whole stack: client, api, database, proxy server.

I recently started [using WSL2 as the backend of the Docker for Windows service](https://docs.docker.com/docker-for-windows/wsl/), and for performance reasons I keep my projects on the Ubuntu VM. This means that I do the command line work in Ubuntu's terminal, which uses Bash.

If you are curious as to why I am using Docker everywhere, check out my article about the pros of using it as a development environment.

{% medium https://medium.com/@danielgaldev/9-reasons-why-you-should-use-docker-as-a-development-environment-96e2ce154194 %}

# The problem

Given the circumstances, I have to type many long commands to start up, manage and stop my stack. I would guess that I use some form of `docker-compose` at least 50 times a day, with the length of the command being 20-60 characters depending on the project. The history feature of Bash is not perfect either, pressing the up and down arrows until you find the command you are looking for requires more attention than you might expect.

![https://images.pexels.com/photos/735911/pexels-photo-735911.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940](https://images.pexels.com/photos/735911/pexels-photo-735911.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940)

Photo [Soumil Kumar](https://www.pexels.com/@soumil-kumar-4325) by on [Pexels](https://www.pexels.com/)

# The goal

I would like to substitute most of the commands I use by 2 or 3 character long mini-commands. I should choose short commands that you are not likely to use. I chose `du`, `dud`, `ds`, `dd`, `da`, `dss` and `dus`.

Note that I'm not going to define a shortcut to every Docker command, as that would be pointless. My goal is that I can use a mini-command at least 8 out of 10 times.

But there is a catch. There are some projects, where we have two different compose files: one for development and one for production. In this case, I would like to use the dev compose file.
This requires a `-f docker-compose.dev.yml` option.

The commands I will define bash functions for:

- `docker-compose up` — starting the containers
- `docker-compose up -d` — starting the containers in detached mode
- `docker-compose stop` — stopping the containers
- `docker-compose exec <servicename> <command>` — attaching to a running service with a shell of our choice
- `docker-compose up <servicename> -d` — starting a specific service in detached mode
- `docker-compose stop <servicename>` — stopping a specific service

As you can see some of these functions will have parameters, which will have default values.

# The solution

I am going to define my functions in the home directory, in a file named `.bash_functions`. This file should be sourced at the beginning of the terminal session, so I extend my `.bashrc` file with the following code:

```bash
if [ -f ~/.bash_functions ]; then
    . ~/.bash_functions
fi
```

Now onto the `.bash_functions` file.

I start with the first part of the command. We need to determine if we need the `-f` option or not.

```bash
function set-compose-command {
    COMPOSE_COMMAND="docker-compose"
    if [ -f docker-compose.dev.yml ]
    then 
        COMPOSE_COMMAND="docker-compose -f docker-compose.dev.yml"
    fi
}
```

I will not call this function manually, however it will be executed at the beginning of every other function. It will set the `COMPOSE_COMMAND` variable in our current shell instance so the other functions just need to attach their specific task at the end. The logic is simple: if the `docker-compose.dev.yml` file exists, apply the `-f` option with the filename.

Next, I define 4 shortcuts that do not require parameters.

```bash
function dud {
    set-compose-command
    sh -c "$COMPOSE_COMMAND up -d"
}

function du {
    set-compose-command
    sh -c "$COMPOSE_COMMAND up"
}

function dd {
    set-compose-command
    sh -c "$COMPOSE_COMMAND down"
}

function ds {
    set-compose-command
    sh -c "$COMPOSE_COMMAND stop"
}
```

The next two functions require one argument each. Without an argument, they will fail.

```bash
# Stop service
function dss {
    if [ -z $1 ]; then
        echo "Please specify a service."
        return 1
    fi
    set-compose-command
    sh -c "$COMPOSE_COMMAND stop $1"
}

# Start service
function dus {
    if [ -z $1 ]; then
        echo "Please specify a service."
        return 1
    fi
    set-compose-command
    sh -c "$COMPOSE_COMMAND up -d $1"
}
```

The functions check if the user supplied at least one argument, and exit with a failing status if not.

The last function has two parameters, both of which have default values.

```bash
function da {
    local service=${1:-dev}
    local shell=${2:-sh}
    set-compose-command
    sh -c "$COMPOSE_COMMAND exec $service $shell"
}
```

The reason for the default values is that I attach to a `sh` shell in the container 90% of the time (I mostly use alpine images and they don't have `bash`), and if I only have one service in my compose file, I will most likely name it `dev`, hence the default service name.

### Conclusion

My docker-compose workflow is now faster and also more comfortable. No more typing the same long commands over and over again.

This is me starting up an environment, making some changes inside and then stopping it when I'm finished:

```bash
den@workstation:~/work/myproject$ dud
Starting myproject_myservice_1 ... done
den@workstation:~/work/myproject$ da myservice
/usr/src/myproject # touch somefile.txt
/usr/src/myproject # ^D
den@workstation:~/work/myproject$ ds
Stopping myproject_myservice_1 ... done
den@workstation:~/work/myproject$
```

![https://images.pexels.com/photos/5483064/pexels-photo-5483064.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940](https://images.pexels.com/photos/5483064/pexels-photo-5483064.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940)

Photo by [cottonbro](https://www.pexels.com/@cottonbro) on [Pexels](https://www.pexels.com/)

Keep in mind that you might not need the exact functions I did, or you might need more. It would be best if you paid some attention to which commands you use most often in your workflow, and define functions for those.

You also don't have to be a bash expert or even an intermediate level script developer to write your custom functionalities. There are plenty of resources to help you, as long as you are not new to programming and know what to search for.

I hope you have a nice day. Work smarter, not harder.

---

If you're curious about Docker and want to try it out in development or in production, check out these articles to get started:

{% medium https://medium.com/free-code-camp/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b %}

{% medium https://towardsdatascience.com/learn-enough-docker-to-be-useful-b7ba70caeb4b %}