
72.tmpディレクトリの話3
ナックス「今日はtmpディレクトリの話その3です」
デビー君「はーい」
ナックス「皆さん、前回の説明を聞いて『つまり、tmpディレクトリでファイルやフォルダを作ると、特定のタイミングでLinuxが勝手に削除してくれるんだな?』と思っていることでしょう」
デビー君「うん」
ナックス「つまり、『わざわざプログラム側で削除する処理を書かなくてもいいや』って思ってる」
デビー君「うん」
ナックス「しかし、おそらく世の中で言われる『お行儀が良い』プログラムというのは、tmpディレクトリに自分で作ったテンポラリファイルは自分で消します」
デビー君「えぇっ!?なんで?じゃあ、せっかく『特定のタイミングで中のファイルやディレクトリを消す』という機能を持つtmpディレクトリの意味が無くない!?」
ナックス「『お行儀が悪い』プログラムは、確かに削除をtmpディレクトリに任せてしまったりしています。しかし例えばユーザーがtmpディレクトリに特別な設定をしていて、削除タイミングが『100年に一度』とかになってたとしたら?」
デビー君「それはユーザーが悪い!」
ナックス「そうです。確かにそれはユーザーが悪いと言えるかもしれません。でも、ユーザーが自分の意思とかじゃなくて、設定を間違ってしまってそういう状態になっている可能性もあります。プログラムというのはあらゆる問題を想定して、できるだけユーザー側に負担がいかないように作るものです。例えばデビーくん。Linuxを初めて使い始めた頃、例えば画像収集アプリを手に入れて何度か画像収集していて、突然Linuxが『tmpディレクトリがいっぱいです』なんてエラーを表示してきたら、デビーくんは対応できました?」
デビー君「うーん、初めての頃なら、ファイルを削除するrmコマンドを知らないし、そもそも『ディレクトリ』がなんなのかもわからないしtmpディレクトリと言われても意味不明……」
ナックス「そうでしょう。でも、これを『Linux初心者ユーザーの自己責任』とか言っていたら、Linuxを新しく使い始めてくれるニューユーザーが、全く増えてくれません。なので『お行儀が良いプログラム』は、tmpディレクトリに自分が作ったテンポラリファイルは、自分で削除するのです」
デビー君「自分自身で削除するとするなら、そもそもtmpディレクトリにテンポラリファイルを作る意味なくないかな?」
ナックス「では、もし私達がこれから作るプログラムがテンポラリファイルを作る処理まではうまく動いたけど、テンポラリファイルを削除する処理の前に、何かが原因でプログラムが中断されたらどうでしょう?テンポラリファイルが残ったままになってしまいます。tmpディレクトリの外にテンポラリファイルを作ったなら誰が消してくれるというのでしょう?」
デビー君「えー?テンポラリファイルを削除する前にプログラムの中断とかあるかなあ?」
ナックス「例えばネットワークが不調で画像をネットワーク先から取得するのに時間がかかりすぎて、ユーザー自身が待てずにCtrlキーとCキーを押してプログラムを中断するとか」
デビー君「あー。なるほど。それは確かにあるかも……」
ナックス「というわけで、基本的にはテンポラリファイルはtmpディレクトリに作るようにしましょう。でもtmpディレクトリの機能を全面的に信じるのではなく、『お行儀の良い』プログラムとして、削除自体はプログラム自身が行いましょう」
デビー君「はーい」
デビー君「……ん?待てよ?削除ってrmコマンドを使うんだよね?」
ナックス「そうですよ?」
デビー君「これから作るプログラムってシェルスクリプトだよね?」
ナックス「そうですよ?」
デビー君「シェルスクリプトってこれからやるコマンド処理を事前に全部ファイルに記述するあれだよね?」
ナックス「そうです。あれです」
デビー君「71.tmpディレクトリの話2を見ると、mktempコマンドを使うことになると思うんだけど」
ナックス「はい。その予定です」
デビー君「mktempコマンドって勝手にtmpディレクトリの下に作るファイル名を決めるよね?」
ナックス「はい」
デビー君「つまり、事前にtmpディレクトリの下に出来るファイル名が分からない」
ナックス「はい」
デビー君「rmコマンドを使うときは削除するファイル名を指定しないといけない」
ナックス「はい」
デビー君「ファイル名が分からないのに、事前にシェルスクリプトに『rmコマンドでこのファイルを削除してください』なんていう処理は書けない……!!」
ナックス「!!」
デビー君「っていうか、事前にファイル名がわからないから、削除処理の前に、そもそもファイルへの書き込み処理もかけない!!」
ナックス「!!」
デビー君「つまりmktempコマンドは……一見便利なコマンドに見せかけて、実はLinux初心者を騙す、全く使い物にならないコマンド!!」
ナックス「違うよ。落ち着いてデビー君。前回のmktempコマンドの実行例をもう一度見てみよう」
$ mktemp /tmp/tmp.Tv5zhSIZuI
ナックス「mktempってコマンドを打つと、/tmp/tmp.Tv5zhSIZuIって表示されてます」
ナックス「そして19.Linuxの一般ユーザーを削除する。userdelコマンドの雑談で、Linuxが『何もアピールしてこない時』は基本的にコマンドは成功しています。エラーが起きたときだけ『エラーが出た!』って叫びます。そう、まるでLinuxは無愛想な女の子みたい──っていう話をしました」
デビー君「うん」
ナックス「しかし今回、mktempコマンドを打つと、無言ではなくて『/tmp/tmp.Tv5zhSIZuI』って返答しています。エラーじゃないのに……!」
デビー君「た、確かに!!」
ナックス「ここから何が推測できますか!?デビー君!!」
デビー君「ま、まさか……無愛想な彼女だったLinuxが、やっと僕とのコミュニケーションに慣れてきて、心を開き始めてる……?」
ナックス「何その素敵なストーリー……!」
デビー君「こんなにずっとLinuxを使ってるんだもの。そりゃあ、いくらシャイなこいつでも、心を開くってもんさ!」
ナックス「おいおい、俺にラブラブなところを見せつけるんじゃねぇよ!ハッハッハッハッハ!って違います!!」
デビー君「違うの?」
ナックス「このmktempっていうコマンドを使うと、表示される/tmp/tmp.Tv5zhSIZuIっていうやつは、実は変数に入れられます!」
デビー君「変数!?」
ナックス「変数が何だったか忘れてるなら30.シェルスクリプトでプログラミングする前の予習。echoコマンド。exprコマンド。\によるエスケープ処理。をチェックしてみてください」
ナックス「というわけで、以下、コマンドだけで説明する『mktempコマンドと変数使えばシェルスクリプトでもmktempコマンド使えるよ解説』です。一番最初のa=`mktemp`のところは、mktempをバッククォートで囲むのがポイントだよ!」
$ a=`mktemp` $ echo $a /tmp/tmp.0vs8cIVny9 $ echo 'おはよう' > $a $ cat $a おはよう $ ls /tmp tmp.0vs8cIVny9 $ rm $a $ ls /tmp [tmp.0vs8cIVny9ファイルが削除されている]
ナックス「雰囲気分かった?」
デビー君「雰囲気分かった!」
ナックス「次回は戻り値の話か、もしくはシェルスクリプト作成開始の話(73.画像収集あきらめた)」