Bash trap in function, but executed when entire script exits

bashshell-script

I'm wondering if something like this is possible.

function get_temp_dir() {
    local tmp_dir=$(mktemp -d)
    trap "{
           rm -r $tmp_dir
       }" EXIT
    echo $tmp_dir
}

temp=$(get_temp_dir)

# I'd like to $temp for the duration of this script, and deleted
# when this current scope ends, not when the function scope ends.

I've seen other scripts achieve the same effect using global arrays with a single trap function that enumerates the array and does something with it. I'd like to avoid that if I can.

I'm also aware that I could just create one tmp directory, and create multiple tmp directories within said directory. However, I'd like to use this approach because it is broadly usable for other things, such as mount/unmount.

Any ideas? Thanks in advance.

edit: So, TRAP does get called when the shell script ends, however, in my original question, I was using a subshell ($()). I got it working after reformatting my code to this:

#!/usr/bin/env bash

function get_temp_dir() {
    local tmp_dir=$(mktemp -d)
    trap "{
           rm -r $tmp_dir
       }" EXIT
    retval=$tmp_dir
}

get_temp_dir
tmp_dir=$retval

ls $tmp_dir

Best Answer

I think you're looking for the RETURN signal:

[...] If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell.
[...] If a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a script run by the . or source builtins finishes executing.

Example:

$ bash
$ trap "echo shell exiting" EXIT
$ fn() { trap "echo function exiting" RETURN; }
$ fn
function exiting
$ (fn)
function exiting
$ value=$(fn); echo "$value"
function exiting
$ exit
shell exiting

and, germaine to the question:

$ f2() { 
    local tmp=$(mktemp)
    trap 'rm "$tmp"' RETURN
    echo "$tmp"
    date >> "$tmp"
    cat "$tmp"
}
$ f2
/tmp/tmp.MHpI20X0a1
Fri May 11 14:29:01 EDT 2018
$ ls -l /tmp/tmp.MHpI20X0a1
ls: cannot access '/tmp/tmp.MHpI20X0a1': No such file or directory
Related Question