我有一个使用 启动测试环境的脚本docker-compose
。该脚本通过 less 将许多 docker 容器的混合 stdout 通过管道传输到 stdout:
# This is part of a larger script with some setup and teardown.
$ docker-compose up --build | less +F -r
less
此处显示了不良行为:当点击Ctrl+时C,docker-compose
收到它并自行关闭。所需的行为只是中断以下 ( +F
) 功能less
(就像查看大型日志时所做的那样)。
我想在最佳情况下实现什么:用第一个Ctrl+中断以下内容,并在第二个+C上退出整个测试环境。CtrlC
我玩了一下并尝试了以下操作:
- 注册一个
trap 'do_exit' SIGINT
将实现上述逻辑的。但仍然在+docker-compose
上退出。CtrlC - 用于
trap '' SIGINT
完全捕获 SIGNT。docker-compose
但仍然凭空得到了Ctrl+ 。C
另一个观察:
这适用于zsh
:((trap '' SIGINT && docker-compose up --build | less +F -r)
它根本不对 SIGINT 做出反应)同一行在 bash 中的行为不同,并被 SIGINT 杀死。
这是完整的(有问题的)脚本供参考:
#!/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
有这方面的解决办法或者经验吗?
--
编辑:我也尝试过这里的解决方案,但没有成功:
答案1
读完这篇文章后我明白了:
- https://en.wikipedia.org/wiki/Process_group
- https://www.gnu.org/software/bash/manual/html_node/Job-Control.html#Job-Control
解决方案是set -m
在脚本开始处执行。这会导致 bash 为每个进程创建一个新的进程组,而不是导致将 SIGINT 发送到脚本中的每个进程。
作为参考,固定脚本如下所示:
#!/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