Ruby无Shell环境下响应TERM信号时退出码为1的问题
When Ruby receives a TERM signal, it normally exits with code 143 (calculated as 128 + 15, since TERM corresponds to signal 15), which means it successfully responded to the signal. But when running Ruby scripts without a shell wrapper (like using Docker's exec-form CMD), the exit code shifts to 1. Here are two Docker test cases to show this difference clearly:
With Shell Environment
In this setup, Docker uses /bin/sh -c to run the command (the default shell form for CMD):
FROM ruby:alpine CMD ruby -e "Process.kill('TERM', Process.pid)" # Shell-form command
Run these commands to test:
docker build -t term_shell . > /dev/null docker run term_shell
Output:
Terminated
Check the exit code:
echo $?
Result:
143
Without Shell Environment
Here, we use Docker's exec-form CMD (array syntax), which runs Ruby directly as the container's PID 1 process, no shell involved:
FROM ruby:alpine CMD ["ruby", "-e", "Process.kill('TERM', Process.pid)"] # Exec-form (no shell)
Test commands:
docker build -t term_noshell . > /dev/null docker run term_noshell
(You won't see the "Terminated" message here—there's no shell to print it.)
Check the exit code:
echo $?
Result:
1
Why the Difference?
When using the shell form, the shell is the container's PID 1 process. It spawns Ruby as a child, and when Ruby sends a TERM signal to itself, it exits with code 143. The shell then propagates this exit code to the container.
In the exec form, Ruby is PID 1. Linux treats PID 1 specially: even though Ruby handles the TERM signal by exiting, the exit code convention for PID 1 differs from regular processes. This leads to the unexpected exit code of 1 instead of 143.
内容的提问来源于stack exchange,提问作者iGEL

