Some examples of my own "real-world" use-cases where I couldn't come up with better alternatives and eval
just gets the job done neatly.
A "conditional-expansion" use-case. Here I want to use a redirection only if $rmsg_pfx
has some value:
eval 'printf -- %s%s\\n "$rmsg_pfx" "$line" '"${rmsg_pfx:+>&2}"
I couldn't do it without eval
because then the >&2
bit would expand as an argument for printf
instead of as its redirection.
I could instead duplicate that line to account for $rmsg_pfx
being empty or not, but that would be.. well.. code duplication.
Speaking of redirections, and as an "indirection" use-case, I like relying on the {varname}>&...
redirection syntax, which I emulate POSIXly like in below:
# equivalent of bash/ksh `exec {rses_fd0}>&- {rses_fd1}<&-` redirection syntax
eval "exec $rses_fd0>&- $rses_fd1<&-"
The above is for closing fds, and likewise I'm doing an analogous indirection for emulating the opening of fds. Obviously $rses_fd0
and $rses_fd1
are script's internal variables, completely under its control from start to end.
Sometimes I had to use eval
to simply "protect" snippets of shell code meant to target specific shells while not disrupting others.
For instance the piece of code below is from a script which is to be portable (POSIXly) while also embedding a few shell-specific optimizations:
sochars='][ (){}:,!'"'\\"
# NOTE: wrapped in an eval to protect it from dash which croaks over the regex
eval 'o=; while [[ "$s" =~ ([^$sochars]*)([$sochars])(.*) ]]; do
...
done'
dash
simply chokes on unknown (but direct) syntax at the lexical level, even when such syntax never gets in the actual code-path.
Another "protection" use-case, in a different sense. Sometimes I just can't be bothered of having to invent "unlikely" names for save&restore purposes. Such as in the case below where I just want $r
's value to be preserved:
# wrapped in eval just to make sure that $r is not overwritten by (the call chain of) coolf
eval '
coolf "$tmp" || return "$lerrno"'"
return $r
"
I actually use often the trick above to preserve exit statuses from loop-suites while also doing cleanup operations, as in:
done <&3
eval "unset ret vals; exec 3<&-; return $?"
}
Or in cases similar to the above, as a "deferred execution":
done
# return boolean set by loop while also unsetting it
eval "unset ok; ${ok:-false}"
}
Note that one implied intention of both snippets above is to not leave "artifacts" from the function execution, especially when the function is meant to be run interactively. For the latter case I could instead do:
[ "${ok:-false}" = false ] && { unset ok; return 1; } || { unset ok; return 0; }
but looks quite rough to me.
Finally I had some occasional use-cases where I wanted/needed to amend, or extend, a function just slightly and on a call basis, perhaps for small behavioral changes or to support some hooking from the caller. Like a callback but in an "inline" fashion, which seemed much less cumbersome particularly when the hook snippet needs access to the function's own $@
arguments. Naturally such snippets, fed thru variables to be subsequently eval
-ed by the function, are either entirely static/handmade themselves or heavily pre-controlled/sanitized.
eval
on them - I can't come up with a good reason off the top of my head why you would want to do this, though. – Panki Mar 23 '21 at 15:07eval
is only evil if not called properly, but not much more so thansh
,[
,[[..]]
,sed
,printf
..., all those commands than can introduce ACE vulnerabilities when not used properly. – Stéphane Chazelas Mar 23 '21 at 16:48echo "something$(somecommandoutput)" | bash
could be consideredevil
too? (since you mentionedsh
,sed
etc) @StéphaneChazelas – Nordine Lotfi Mar 23 '21 at 16:49eval
is just another way to invoke your shell's interpreter. It's less obvious for commands like[
,read
orprintf
which could be seen as more evil for that reason. – Stéphane Chazelas Mar 23 '21 at 16:5300000000
to terminate input. Theneval
the string. It takes 12 * 8 = 96 colour sensings to enterprint(':)')
. Oh, wait... you said "useful"... – Luke Sawczak Mar 25 '21 at 17:54useful
is a bit broad but, in your case, it could be considered that, given this is in the context of teaching...beside that, this probably wouldn't apply here since it use Python (and this post is more or less shell-centric) @LukeSawczak I appreciate that you talked about your experience though! it is an interesting use of eval. – Nordine Lotfi Mar 25 '21 at 17:59