Executing 'bash -c' in 'docker exec' command

AdrienW picture AdrienW · May 7, 2018 · Viewed 11.5k times · Source

Context: I'm trying to write a shortcut for my daily use of the docker exec command. For some reasons, I'm experimenting the problem that my output is sometimes broken when I'm using a bash console inside a container (history messed up, lines overwrite each other as I'm writing, ...)

I read here that you could overcome this problem by adding some command before starting the bash console.


Here is a relevant excerpt of what my script does

#!/bin/bash
containerHash=$1
commandToRun='bash -c "stty cols $COLUMNS rows $LINES && bash -l"'

finalCommand="winpty docker exec -it $containerHash $commandToRun"
echo $finalCommand
$finalCommand

Here is the output I get:

winpty docker exec -it 0b63a bash -c "stty cols $COLUMNS rows $LINES && bash -l"
cols: -c: line 0: unexpected EOF while looking for matching `"'
cols: -c: line 1: syntax error: unexpected end of file

I read here that this had to do with parsing and expansion. However, I can't use a function or an eval command (or at least I didn't succeed in making it work).

If I execute the first output line directly in my terminal, it works without trouble.

How can I overcome this problem?

Answer

Arount picture Arount · May 7, 2018

It's not Docker related, but Bash (In other words, the docker's part of the command works well, it's just bash grumbling on the container like it would grumble on your host):

Minimal reproducible error

cmd='bash -c "echo hello"'
$cmd

hello": -c: line 0: unexpected EOF while looking for matching `"'
hello": -c: line 1: syntax error: unexpected end of file

Fix

cmd='bash -c "echo hello"'
eval $cmd

hello

Answer

foo='docker exec -it XXX bash -c "echo hello"'
eval $foo

This will let you execute your command echo hello on your container, now if you want to add dynamic variables to this command (like echo $string) you just have to get rid of single quotes for double ones, to make this works you will have to escape inner double quotes:

foo="docker exec -it $container bash -c \"echo $variable\""

A complete example

FOO="Hello"
container=$1
bar=$2

cmd="bash -c \"echo $FOO, $bar\""
final_cmd="docker exec -it $container $cmd"

echo "running command: \"$final_cmd\""
eval $final_cmd

Let's take time to dig in,

  • $FOO is a static variable, in our case it works exactly like a regular variable, just to show you.
  • $bar is a dynamic variable which takes second command line argument as value
  • Because $cmd and $final_cmd uses only double quotes, variables are interpreted
  • Because we use eval $final_cmd command is well interpreted, bash is happy.

Finally, a usage example:

bash /tmp/dockerize.sh 5b02ab015730 world

Gives

running command: "docker exec -it 5b02ab015730 bash -c "echo Hello, world""
Hello, world