Docker, bash and invisible characters
Consider the following Dockerfile, perhaps the simplest in existence, which echoes back the argument given to it:
FROM mcr.microsoft.com/dotnet/core/runtime:3.0-alpine ENTRYPOINT ["echo"]
And this small script,
test.sh, which builds the container, runs it with the argument 42 and verifies that the output is the same as the input.
#!/usr/bin/env bash docker build -t hjerpbakk/example . ARGUMENT="42" RESULT=$(docker run --rm -it hjerpbakk/example "$ARGUMENT") if [ "$RESULT" = "$ARGUMENT" ]; then echo "container ran successfully"; exit; fi echo "container failed. Expected:" echo "$ARGUMENT" echo "but got:" echo "$RESULT" exit 1;
Surprisingly, 42 is not equal to 42. What is going on here?
Docker output gotcha
After a little bit of DuckDuckGo-ing, it turns out Docker sometimes adds a carriage return at the end of the output. To remove a superfluous carriage return, the tr command can be used.
Thus the script can be changed to pipe the result through
tr, removing any
\r in the output:
RESULT=$(docker run --rm -it hjerpbakk/example "$ARGUMENT" | tr -d '\r')
It feels hacky, but the script completed successfully.
In the docker-command above I’ve used
- -i is short for –interactive. Keep STDIN open even if unattached.
- -t is short for –tty. Allocates a pseudo-terminal that connects your terminal with the container’s STDIN and STDOUT.
Some more research revealed that
-t is responsible for the extra
\r. For my use, neither
-t are needed. Removing
-it also removes the need for the hack, making the final script:
RESULT=$(docker run --rm hjerpbakk/example "$ARGUMENT")
As Dave Agans says in the book Debugging: The 9 Indispensable Rules for Finding Even the Most Elusive Software and Hardware Problems, the first order of business is to see the system fail. Only then can you can analyze how it fails and finally fixed the problem when you know why it fails.
If you don’t understand why you fixed the problem, as in the
tr hack above, you haven’t actually fixed it.