Temporary operation in a temporary directory in shell script
Asked Answered
R

3

10

I need a fresh temporary directory to do some work in a shell script. When the work is done (or if I kill the job midway), I want the script to change back to the old working directory and wipe out the temporary one. In Ruby, it might look like this:

require 'tmpdir'

Dir.mktmpdir 'my_build' do |temp_dir|
  puts "Temporary workspace is #{temp_dir}"
  do_some_stuff(temp_dir)
end

puts "Temporary directory already deleted"

What would be the best bang for the buck to do that in a Bash script?

Here is my current implementation. Any thoughts or suggestions?

here=$( pwd )
tdir=$( mktemp -d )
trap 'return_here' INT TERM EXIT
return_here () {
    cd "$here"
    [ -d "$tdir" ] && rm -rf "$tdir"
}

do_stuff # This may succeed, fail, change dir, or I may ^C it.
return_here
Romeu answered 18/3, 2010 at 19:7 Comment(3)
You can use 'cd -' to return to the previous directory. That way you don't have to save the name of the old directory. Another option would be to use pushd/popd.Redding
I explicitly stored the directory to give do_stuff freedom to change directory, change the pushd queue, etc. However in my case I know do_stuff doesn't use pushd/popd so that would be a much nicer implementation!Romeu
I would not trust cd - (the script may have cd-ed multiple places before the trap runs).Rouse
R
15

Here you go:

#!/bin/bash
TDIR=`mktemp -d`

trap "{ cd - ; rm -rf $TDIR; exit 255; }" SIGINT

cd $TDIR
# do important stuff here
cd -

rm -rf $TDIR

exit 0
Redding answered 18/3, 2010 at 21:53 Comment(2)
You can add EXIT to your trap and you won't have to do the explicit rm.Bebe
Thanks! That's a good pattern. I updated my question with my own version. I have not been exiting 255 like that though.Romeu
I
1

The usual utility to get yourself a temporary directory is mktemp -d (and the -p option lets you specify a prefix directory).

I'm not sure if "I want to trap" was a question too, but bash does let you trap signals with (surprise!) trap - see the documentation.

Inglenook answered 18/3, 2010 at 19:17 Comment(1)
Thanks. I know how to use the components. I am asking around for people's preferred ways of putting them all together.Romeu
R
1

Assuming mktemp -d returns a relative pathname, I would forget about $here and do this instead:

tdir=
cleanup() {
    test -n "$tdir" && test -d "$tdir" && rm -rf "$tdir"
}
tdir="$(pwd)/$(mktemp -d)"
trap cleanup EXIT
trap 'cleanup; exit 127' INT TERM

# no need to call cleanup explicitly, unless the shell itself crashes, the EXIT trap will run it for you
Rouse answered 19/3, 2010 at 1:18 Comment(1)
Could you please explain why are you using two traps?Traitorous

© 2022 - 2024 — McMap. All rights reserved.