ShellScript 一時ディレクトリを利用しよう

Shellで一時ディレクトリを利用する

シェルスクリプトで一時ディレクトリを利用したい場合は、よくあります。
そんなときに使えるテンプレをここに記載しておきます。

一時ディレクトリ利用のテンプレ

tempdir_sample.sh

#!/bin/bash
set -ux

# 一時ディレクトリを作成 (Pathを変数に代入しておく)
temp_dir=$(mktemp -d)

# スクリプト終了時に一時ディレクトリを削除
trap 'rm -rf $temp_dir' EXIT

# TODO: ここで一時ディレクトリでやりたい処理を
touch $temp_dir/hoge
touch $temp_dir/piyo
touch $temp_dir/foo
ls $temp_dir

echo "done"

mktempコマンドで一時ディレクトリを作成しています。
作成したディレクトリは、スクリプト終了時に削除してほしい場合は、
trapコマンドを利用します。

実行したときの結果は下記のとおり。
set -x としているので、実行コマンドは表示しています。

$ bash tempdir_sample.sh
++ mktemp -d
+ temp_dir=/var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.iEIexH9M
+ trap 'rm -rf $temp_dir' EXIT
+ touch /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.iEIexH9M/hoge
+ touch /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.iEIexH9M/piyo
+ touch /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.iEIexH9M/foo
+ ls /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.iEIexH9M
foo hoge    piyo
+ echo done
done
+ rm -rf /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.iEIexH9M

一時ディレクトリが作成され、
スクリプト終了時にはディレクトリが削除できているのがわかります。

サブシェルを利用したテンプレ

サブシェルを利用すると、
特定の処理だけ一時ディレクトリで作業させる事もできます。

tempdir_with_subshell_sample.sh

#!/bin/bash
set -ux

# 括弧を使うとサブシェルになる
(
  echo "sub-shell start"

  # 一時ディレクトリ作成
  temp_dir=$(mktemp -d)
  # サブシェル終了時に発動する
  trap 'rm -rf $temp_dir' EXIT

  # サブシェル内のディレクトリ移動は親シェルに影響しない
  cd $temp_dir

  # TODO: ここで一時ディレクトリ内でやりたい処理を
  touch hoge
  touch piyo
  touch foo
  ls

  echo "sub-shell done"
)

echo "done"

cdする場合、
スクリプト実行したシェル自体のカレンドディレクトリも変わってしまう。
サブシェル内でcdするのであれば、
親シェルに影響を与えないのでオススメです。

実行結果がこちら↓

$ bash tempdir_with_subshell_sample.sh
+ echo 'sub-shell start'
sub-shell start
++ mktemp -d
+ temp_dir=/var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.NsxyR6RE
+ trap 'rm -rf $temp_dir' EXIT
+ cd /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.NsxyR6RE
+ touch hoge
+ touch piyo
+ touch foo
+ ls
foo hoge    piyo
+ echo 'sub-shell done'
sub-shell done
++ rm -rf /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.NsxyR6RE
+ echo done
done

trap処理も、サブシェルで実行しているので
サブシェル終了時に一時ディレクトリ削除がおこなわれているのがわかります。

mktempコマンドについて

mktempコマンドは、
TMPDIR 環境変数をみて一時ファイルを作成するコマンド。

$ echo $TMPDIR
/var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T

Macの場合だと、↑こんな感じになってるはず。

一時ファイルの作成

普通につかうと、
一時ディレクトリではなくファイルが作成されます。

作成されるファイルはランダムでユニークな名称で作成されます。

$ mktemp
/var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.IdOVCZul

$ ls -lha /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.IdOVCZul
-rw-------  1 tyab  staff     0B  3  7 12:58 /var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.IdOVCZul

mktempコマンドは、作成した一時ファイルのPATHを出力します。
ShellScriptでは、この出力をShell変数に代入して利用する。

-t オプションでプレフィックスを指定することもできます。

$ mktemp -t hoge
/var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/hoge.0XLPF25S

一時ディレクトリの作成

ファイルではなく、一時ディレクトリを作成したい場合は、
-d オプションを使います。

$ mktemp -d
/var/folders/d9/h72gyc550rg_tw97v9c72hl80000gn/T/tmp.XokR90r0

$ ls -lha $TMPDIR
drwx------   2 tyab  staff    68B  3  7 13:02 tmp.XokR90r0

同じように、$TMPDIR配下にユニークな名称でディレクトリが作成され、
作成されたディレクトリのPATHが出力されます。

コマンドのオプション

-d-t オプションくらいを知っていれば問題ないですが、
コマンドのマニュアルは一度みておくと良いです。

$ man mktemp

NAME
     mktemp -- make temporary file name (unique)

SYNOPSIS
     mktemp [-d] [-q] [-t prefix] [-u] template ...
     mktemp [-d] [-q] [-u] -t prefix

OPTIONS
     The available options are as follows:

     -d      Make a directory instead of a file.

     -q      Fail silently if an error occurs.  This is useful if a script does not want
             error output to go to standard error.

     -t prefix
             Generate a template (using the supplied prefix and TMPDIR if set) to create
             a filename template.

サンプル

mktempコマンドのマニュアルに、
サンプルも載っているので参考にするといいでしょう。

EXAMPLES
     The following sh(1) fragment illustrates a simple use of mktemp where the script
     should quit if it cannot get a safe temporary file.

           tempfoo=`basename $0`
           TMPFILE=`mktemp /tmp/${tempfoo}.XXXXXX` || exit 1
           echo "program output" >> $TMPFILE

     To allow the use of $TMPDIR:

           tempfoo=`basename $0`
           TMPFILE=`mktemp -t ${tempfoo}` || exit 1
           echo "program output" >> $TMPFILE

     In this case, we want the script to catch the error itself.

           tempfoo=`basename $0`
           TMPFILE=`mktemp -q /tmp/${tempfoo}.XXXXXX`
           if [ $? -ne 0 ]; then
                   echo "$0: Can't create temp file, exiting..."
                   exit 1
           fi

trapコマンドについて

mktempコマンドは、ファイルやディレクトリを作成してくれますが、
使い終わったら自動で削除してくれるような機能はありませんので、
trapでrmコマンドを実行するようにすると良いでしょう。

trapコマンドは指定したコマンド文字列を、
特定のタイミングで実行させる事ができます。

よく使うのはEXITでしょう。
ShellScriptであれば、スクリプトが終了した際に実行される事になります。

trap 'echo "This message shows at exiting."' EXIT

もし、サブシェル内で利用すれば、
サブショル終了のタイミングでも実行できます。

まとめ

  • mktemp -d コマンドで一時ディレクトリを作成できる
  • trap コマンドでスクリプト終了時に一時ディレクトリ削除できる
  • サブシェルを使えば、特定の処理だけ一時ディレクトリで作業ができる

コメントを残す