即使进程终止后,bash 等待进程也会停止

即使进程终止后,bash 等待进程也会停止

我正在尝试编写脚本来确定 mariadb 测试容器的启动。port: 3306是最后一行podman logs -f,在此之后没有太多预期(因此尝试终止podman logs进程而不是依赖于 SIGPIPE)。

  set -x -v; \
  podman run -d --name mdb_test -P -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1  mariadb:10.6 ; \
  podman logs -f mdb_test 2>&1 | grep -m1 'port: 3306' & \
  pid_grep=$! ; \
  pid_podman_logs=$(jobs -p); \
  jobs; \
  wait $pid_grep; \
  kill $pid_podman_logs; \
  port=$(podman port mdb_test 3306); \
  mysql -u root --protocol tcp --port ${port#*:}  -e 'select version()';

输出:

+ set -x -v
+ podman run -d --name mdb_test -P -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 mariadb:10.6
299b645a84b278d2ffcfb776bf12cf282a0695131bf77a02f0c7701a9ea1868b
[1]+  Done                    podman logs -f mdb_test 2>&1 | grep -m1 'port: 3306'
[1] 2414801
+ pid_grep=2414801
+ podman logs -f mdb_test
+ grep -m1 'port: 3306'
++ jobs -p
+ pid_podman_logs=2414800
+ jobs
[1]+  Running                 podman logs -f mdb_test 2>&1 | grep -m1 'port: 3306' &
+ wait 2414801
Version: '10.6.1-MariaDB-1:10.6.1+maria~focal'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

我想知道为什么 shell 已经停止wait并且没有进展,即使grep已经终止(并且podman logs仍在运行)。

欢迎任何其他脚本改进。

编辑更简单的版本:

set -x -v ; (echo "bob"; sleep 100000) | grep -m1 bob & pid_grep=$!; pid_echo=$(jobs -p); jobs ; wait $pid_grep; kill $pid_echo; echo ready
+ set -x -v
[1] 2417616
+ pid_grep=2417616
+ grep -m1 bob
+ echo bob
+ sleep 100000
++ jobs -p
+ pid_echo=2417615
+ jobs
[1]+  Running                 ( echo "bob"; sleep 100000 ) | grep -m1 bob &
+ wait 2417616
bob

在另一个 shell 中查看 ps,grep 已完成。

答案1

IMO,你的处理方式完全错误。

查看进程是否正在侦听端口并正确响应的正确方法是连接到该端口并进行查询。 grep 日志的最佳效果是告诉您过去某个时间正在监听,而不是现在实际上正在监听 - 它可能在日志条目和现在之间的某个时间已经死亡。

因此,启动 mysql 并使用 while 循环来查看 mysql 是否正确响应。在循环的每次迭代中休眠几秒钟。

您的整个脚本可以替换为如下内容 - 不需要后台作业、等待、杀死 pid 等:

podman run -d --name mdb_test -P -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1  mariadb:10.6

# I'm not sure why you need to do this rather than just 'port=3306', but I don't
# know podman. Maybe it's necessary for some kind of namespace port mapping.
port=$(podman port mdb_test 3306)
port=${port#*:}

MYSQL_VERSION=""
while [[ ! "$MYSQL_VERSION" =~ ^Version ]] ; do
   sleep 2
   MYSQL_VERSION=$(mysql -u root --protocol tcp --port "$port"  -e 'select version()')
done
echo "$MYSQL_VERSION"

答案2

coproc 是一种方式:

set -x -v; \
podman run -d --name mdb_test -P -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1  mariadb:10.6 ; \
coproc podman logs -f mdb_test 2>&1; \
pid_podman_logs=${COPROC_PID}; \
grep -m1 'port: 3306' <&"${COPROC[0]}"; \
kill $pid_podman_logs; \
port=$(podman port mdb_test 3306); \
mysql -u root --protocol tcp --port ${port#*:}  -e 'select version()';

输出:

+ set -x -v
+ podman run -d --name mdb_test -P -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 mariadb:10.6
c8bc23b8b7b0c34e1037f28797f34184e768f7def9ee220f2b8760484a2d798e
[1] 2420140
+ pid_podman_logs=2420140
+ grep -m1 'port: 3306'
+ podman logs -f mdb_test
Version: '10.6.1-MariaDB-1:10.6.1+maria~focal'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
+ kill 2420140
++ podman port mdb_test 3306
+ port=0.0.0.0:34497
+ mysql -u root --protocol tcp --port 34497 -e 'select version()'
+-------------------------------------+
| version()                           |
+-------------------------------------+
| 10.6.1-MariaDB-1:10.6.1+maria~focal |
+-------------------------------------+
[1]+  Exit 1                  coproc COPROC podman logs -f mdb_test 2>&1

所以对于更简单的版本:

set -x -v ; coproc (echo "bob"; sleep 100000) ; pid_echo=${COPROC_PID};  grep -m1 bob  <&"${COPROC[0]}" <&"${COPROC[0]}" ; kill $pid_echo; echo ready
+ set -x -v
[1] 2418707
+ pid_echo=2418707
+ grep -m1 bob
+ echo bob
+ sleep 100000
bob
+ kill 2418707
+ echo ready
ready

相关内容