Best Practice: Expand At Execution Time
Simple Case
The code you were worried about,
trap 'EXIT' 'rm -f "$TEMPDIR_OR_FILE"'
...really does work; it just looks up TEMPDIR_OR_FILE
when the trap is running, not when it's defined. There's nothing wrong with that: When the trap is running is the best time to look at your temporary file definitions, because that way the rest of your script can change those definitions as appropriate during its execution.
Getting Fancy: Handling An Arbitrary Number Of Temporary Files
Consider the following:
declare -A tempfiles=( )
cleanup() { (( ${#tempfiles[@]} )) && rm -rf -- "${!tempfiles[@]}"; }
trap 'cleanup' EXIT
# ...do some stuff...
tempfiles[something]=$(mktemp -t -d something.XXXXXX)
echo "hello" >"${tempfiles[something]}/greeting"
# ...do more stuff...
tempfiles[something_else]=$(mktemp -t something_else.XXXXXX)
if [[ $keep_something_else ]]; then
# the user wants us to keep this temporary file! remove it from deletion list
unset tempfiles[keep_something_else]
fi
With the above, you define your cleanup function just once, and don't need to know your temporary directories at that time; when you exit, you look up the list as it exists then.
Literal Answer: Expanding At Definition Time
In most cases, it's desirable to expand a variable when a trap is executed, vs when it's defined. However, you're asking to do it the other way.
To do this safely, use printf %q
to generate an eval
-safe version of your filename, and expand that in double quotes when defining the trap.
printf -v tempdir_or_file_q '%q' "$TEMPDIR_OR_FILE"
trap 'retval=$?; rm -rf '"${tempdir_or_file_q}"'; exit "$retval"'
Note that we end the initial single quotes before referencing the variable you want to expand at definition time, expand it in double quotes, end those double quotes and switch back to single quotes after.