Docker: Using Expect script directly in Dockerfile will be complicated

This article will describe using Expect script for keyboard-configuration package automatically installation. However, in conclusion, Expect script should be written in other file.

1 keyboard-configuration package

Installing keyboard-configuration package needs interactive setup for selecting keyboard layout.

By the way, keyboard-configuration package setup will be skipped if /etc/default/keyboard is exists. But there are difficult packages to skip setup like console-setup package.

In that case, you can use Expect script for automated setup.

2 Expect script

The following Expect script will make keyboard-package installation be automatic.

  • Send "\n" to "[More]". Expect script needs escape \\\ to [ and ].
  • Send "50\n" to "Country of origin for the keyboard: ".
  • Send "1\n" to "Keyboard layout: ".
#!/usr/bin/env expect

set timeout -1
spawn apt-get install -y keyboard-configuration
expect {
    "\\\[More\\\]" { send "\n"; exp_continue; }
    "Country of origin for the keyboard: " { send "50\n"; }
}
expect {
    "\\\[More\\\]" { send "\n"; exp_continue; }
    "Keyboard layout: " { send "1\n" }
}
expect eof

"[More]" will be displayed when keyboard layout information string reaches to terminal bottom.

Configuring keyboard-configuration
----------------------------------

The layout of keyboards varies per country, with some countries having multiple
common layouts. Please select the country of origin for the keyboard of this
computer.
[More]

3 Shell script

Convert Expect script to Shell script is as following.

  • \\\ in double quote will be converted to \. In single quote, \\ will be converted to \ but cannot be assined shell variable.
  • printf treats Shell scripts' newline as printf's newline.
#!/bin/sh

apt-get update -y
apt-get install -y expect

printf "
set timeout -1
spawn apt-get install -y keyboard-configuration
expect {
    \"\\\\\\\\\[More\\\\\\\\\]\" { send \"\\\n\"; exp_continue; }
    \"Country of origin for the keyboard: \" { send \"50\\\n\"; }
}
expect {
    \"\\\\\\\\\[More\\\\\\\\\]\" { send \"\\\n\"; exp_continue; }
    \"Keyboard layout: \" { send \"1\\\n\" }
}
expect eof
" | expect

4 Dockerfile

Write Shell script to Dockerfile is as following.

  • With \ at the end of line, Dockerfile treats statement at next line as continued statement. This helps to separate command to multiple line.
  • Dockerfile does not provide command with newline at the end of multiple line. printf needs '\n' in double quote. Multiple command must be combined with ;, && or ||.
  • The response for "[More]" may be unneeded.
FROM ubuntu:16.04

RUN apt-get update -y && \
apt-get install -y expect && \
printf "\
set timeout -1\n\
spawn apt-get install -y keyboard-configuration\n\
expect {\n\
    \"\\\\\\\\\[More\\\\\\\\\]\" { send \"\\\n\"; exp_continue; }\n\
    \"Country of origin for the keyboard: \" { send \"50\\\n\"; }\n\
}\n\
expect {\n\
    \"\\\\\\\\\[More\\\\\\\\\]\" { send \"\\\n\"; exp_continue; }\n\
    \"Keyboard layout: \" { send \"1\\\n\" }\n\
}\n\
expect eof\n\
" | expect

5 Conclusion

Using Expect script directly in Dockerfile needs costs for converting script. You should prepare other expect script or shell script, and copy to container with COPY or ADD of Dockerfile, and run it with RUN of Dockerfile.

FROM ubuntu:16.04

RUN apt-get update -y && apt-get instal -y expect
COPY keyboard-configuration.exp /
RUN expect keyboard-configuration.exp