-
-
Save cedws/ab8da14beb3aad4521ba6b612956a83e to your computer and use it in GitHub Desktop.
#!/bin/sh | |
DEFER= | |
defer() { | |
DEFER="$*; ${DEFER}" | |
trap "{ $DEFER }" EXIT | |
} |
@zapashcanon No problem, thanks for letting me know! I think I've fixed it now.
Yep', I confirm it's fixed. Thanks. :)
This is very prone to shell injection vulnerabilities as it's currently written.
With bash 5.0, you can mitigate that using ${*@Q}
in place of $*
.
With earlier releases, you can use printf -v cmd_q '%q ' "$@"
to generate an eval
-safe escaping of an arbitrary command (stored in the variable $cmd_q
).
Also, consider staying out of the all-caps namespace; as POSIX advises at https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, all-caps names are used for variables that reflect or modify behavior of the shell and other POSIX-specified tools. (Because regular shell variables and environment variables share a single namespace -- setting a shell variable will overwrite any like-named environment variable -- the same conventions apply to both).
The correct noun form of the adjective "idempotent" is "idempotence", not *idempotency*.
An idempotent operation is one that has the same effect whether you apply it once or multiple times.
Not leaking (which your trap
wrapper could help with) is one aspect aspect of this but not the main meaning.
This will not handle spaces correctly, try for example
defer echo "a b" # two spaces between 'a' and 'b'
the output will have one space:
a b
Looking at the ongoing comments on HN and here, I'll go with @charles-dyfis-net's version which handle spaces correctly (bash5.0+ only).
#!/usr/bin/env bash
DEFER=
defer() {
DEFER="${*@Q}; ${DEFER}"
trap "{ $DEFER }" EXIT
}
# some tests
TEMP=$(mktemp)
touch "/tmp/a b"
defer rm -vf "$TEMP" "/tmp/a b"
ls -lsah "$TEMP"
ls -lsah "/tmp/a b"
The solutions for shell seemed too complicated or wrong.
As an addendum (since the suggestions I made above are applicable either to bash 5+ or shells with the ksh93 printf %q
extension such as bash or zsh):
For folks who want both safety and compatibility with /bin/sh
, I'd suggest encapsulating cleanup code in functions (with no arguments -- getting content from variables only) and then passing the names of those functions to defer
. rm_tmp_ab() { rm -vf "$TEMP" "/tmp/a b"; }; defer rm_tmp_ab
f/e.
Hiya,
Sorry to comment here but I didn't find any way to contact you otherwise...
I just wanted to let you know that your RSS feed is kinda broken. As you don't use absolute urls, e.g.
<link>/defer-for-shell/</link>
, then when I read an article on my miniflux instance, if I want to go to the original link, the links points to my domain, e.g.https://rss.zapashcanon.fr/defer-for-shell/
which is wrong.Cheers !