import subprocess SCRIPTS = [ # different ways to exit 'trap "echo EXIT" EXIT', 'trap "echo EXIT" EXIT; exit 1', 'set -e; trap "echo EXIT" EXIT; false', 'trap "echo EXIT" EXIT; kill -INT $$', 'trap "echo EXIT" EXIT; kill -TERM $$', 'trap "echo EXIT" EXIT; kill -KILL $$', # modify exit code during cleanup 'trap "echo EXIT; true" EXIT; exit 1', 'trap "echo EXIT; exit 2" EXIT; exit 1', # proposed solution 1 'trap "echo EXIT" EXIT; trap "trap - INT; trap - EXIT; echo INT; kill -INT $$" INT; kill -INT $$', 'trap "echo EXIT" EXIT; trap "trap - TERM; trap - EXIT; echo TERM; kill -TERM $$" TERM; kill -TERM $$', # proposed solution 2 'trap "echo EXIT" EXIT; trap "exit 130" INT TERM; kill -INT $$', 'trap "echo EXIT" EXIT; trap "exit 130" INT TERM; kill -TERM $$', # subshell 'trap "echo EXIT" EXIT; (trap "echo SUBSHELL EXIT" EXIT)', # functions 'trap "echo EXIT" EXIT; foo() { trap "echo INNER EXIT" EXIT; }; foo', 'trap "echo EXIT" EXIT; foo() { trap "echo RETURN" RETURN; }; foo', ] for script in SCRIPTS: results = {} for shell in ['dash', 'bash', 'zsh', 'busybox sh']: proc = subprocess.run( shell.split(), input=script, capture_output=True, encoding='utf-8' ) key = f'[{proc.returncode}] {proc.stdout!r}' results.setdefault(key, []) results[key].append(shell) print(script) for stdout, shells in results.items(): print(f'{stdout} ({", ".join(shells)})') print()