1

I have a script that boots up a test environment using docker-compose. This script pipes the mixed stdout of many docker containers on stdout through less:

# This is part of a larger script with some setup and teardown.
$ docker-compose up --build | less +F -r

less shows an undesired behavior here: When hitting CTRL-C, docker-compose receives it and shuts down itself. Desired behaviour is only to interrupt the following (+F) feature of less (like it does when viewing e.g. a large log).

What I want to achieve in the optimal case: Interrupt the following with the first CTRL-C and quit the whole test environment on the second CTRL-C.

I've toyed a bit around and tried the following things:

  • Register a trap 'do_exit' SIGINT that would implement the logic above. docker-compose however still exited upon CTRL-C.
  • Use trap '' SIGINT to catch SIGNT totally. docker-compose however still got the CTRL-C out of thin air.

Another observation:

This works in zsh: (trap '' SIGINT && docker-compose up --build | less +F -r) (it does not react to SIGINT at all) The same line behaves differently in bash and is killed by SIGINT.

Here is the full (buggy) script for reference:

#!/usr/bin/env bash

service_name=xxx

for dir in ../1 ../2 ../3; do
    if [ ! -d "$dir" ]; then
      echo "docker compose requires $dir, please check $dir do exist in the same folder level"
      exit 0
    fi
done

docker-compose up --build | less +F -r

if [ ! $? -eq 0 ]; then
    echo "Couldn't start service or Control-C was pressed"
    echo "cleaning up"
    docker-compose down
    exit $?
fi

docker-compose rm --all --force

Any solution or experiences with this?

--

Edit: I've also tried the solutions here without any success:

  • pkill -INT less from another terminal? – muru Mar 6 '18 at 10:09
  • Thanks @muru, pkill -INT less kind of works (only kills less, but not docker-compose), but doesn't really answer the question. Preferably I want to be able to hit Ctrl-C directly in the terminal out of convinience (and I also want to understand how this works...) – Sahib Mar 6 '18 at 10:50
  • Have you tried (trap '' INT && docker-compose up --build) | less +F -R? – Stéphane Chazelas Mar 6 '18 at 11:43
  • Note that your script will also get the SIGINT – Stéphane Chazelas Mar 6 '18 at 11:44
  • @StéphaneChazelas: Thanks. Still pressing CTRL-C will stop docker-compose, while it should only stop the paging mode of less. Can you explain why (docker-compose up --build | less +F -r) is not interruptable in zsh and but is in bash? – Sahib Mar 6 '18 at 12:31
0

I figured it out after reading this:

The solution is to do set -m at the start of the script. This causes bash to create a new process group for each process, not causing SIGINT to be send to every process in the script.

For reference, the fixed script looks like this:

#!/usr/bin/env bash

set -m
set -e

service_name=xxx

for dir in ../1 ../2 ../3; do
    if [ ! -d "$dir" ]; then
      echo "docker compose requires $dir, please check $dir do exist in the same folder level"
      exit 0
    fi
done

TEMP_LOG_FILE=$(mktemp --suffix '-dev-env-log')
(trap '' SIGINT && docker-compose up --build > ${TEMP_LOG_FILE}) &
less +F -r ${TEMP_LOG_FILE}
rm ${TEMP_LOG_FILE}

echo "Less was quit, stopping containers..."


if [ ! $? -eq 0 ]; then
    echo "could not start service or Control-C was pressed"
    echo "cleaning up"
    docker-compose down
    exit $?
fi

docker-compose down
docker-compose rm --all --force

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.