4

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:

5
  • pkill -INT less from another terminal?
    – muru
    Mar 6, 2018 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, 2018 at 10:50
  • Have you tried (trap '' INT && docker-compose up --build) | less +F -R? Mar 6, 2018 at 11:43
  • Note that your script will also get the SIGINT Mar 6, 2018 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, 2018 at 12:31

1 Answer 1

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
1
  • This causes bash to create a new process group for each process, not causing SIGINT to be send to every process in the script. – then why do you still need a trap for SIGINT when running docker-compose? Nov 25, 2020 at 18:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .