Skip to content

Instantly share code, notes, and snippets.

@hraban
Last active September 24, 2018 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hraban/8cdf307c5754a2b547933d7baeb16916 to your computer and use it in GitHub Desktop.
Save hraban/8cdf307c5754a2b547933d7baeb16916 to your computer and use it in GitHub Desktop.
exploring signal handling in bash scripts, subshells and pipelines

Signal catching test

Testing how signals are caught through wrapper scripts and how error values are returned.

Usage

docker build -t test-signals .
docker run --rm --name test-signals test-signals

From another window:

docker kill -s TERM test-signals

This will send a SIGTERM to the running docker container. Do it a few times; results might differ between runs.

#!/bin/bash
set -euo pipefail
while date ; do sleep 3 ; done | python3 signals.py one | python3 signals.py two | cat
FROM node:8-slim
RUN apt-get update && \
apt-get install -y -q \
python3.4 \
&& \
curl -sSL -o /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 && \
chmod +x /usr/local/bin/dumb-init && \
rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["dumb-init", "--"]
WORKDIR /app
COPY . /app
CMD yarn start
{
"scripts": {
"start": "./chained-script.sh"
}
}
#!/usr/bin/env python3
import signal
import sys
class App(object):
def __init__(self, name):
self.name = name
def printsig(self, sig, frame):
self.write("Received {} ({}): {}\n".format(self.signals[sig], sig, frame))
def trapall(self):
self.signals = {}
for name in [x for x in dir(signal) if x.startswith("SIG")]:
i = getattr(signal, name)
self.signals[i] = name
try:
signum = getattr(signal, name)
try:
signal.signal(signum, self.printsig)
except ValueError:
pass
#self.write("Skipping {} (out of range)\n".format(name))
except OSError as m:
pass
#self.write("Skipping {} (not catcheable)\n".format(name))
def write(self, msg):
sys.stderr.write("{}: {}".format(self.name, msg))
def echoloop(self):
for line in sys.stdin:
self.write(line)
# Pass to stdout unchanged to avoid cascading
sys.stdout.write(line)
def main():
name = sys.argv[1]
app = App(name)
app.trapall()
app.echoloop()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment