$TEMPの大量ファイルを「快適に」削除する方法

$TEMPに限らず、特に Windows で、「大量のファイル」に見舞われると、いつまで経っても削除が始まらない、ということは良く経験することだ。

_2015-04-10 01:58投稿

「特に Windows で」は、必ずしも「だから Windows はタコなんだ」とばかりも言えない事情もあって。「削除の準備をしています」に「すんな、準備、とっとと始めろい」と思うのは人情だが、これは本当に「削除のアンドゥ」のため、や、登録されたシェル拡張を呼び出したり、と忙しい。あまり責めないでやってくれ。

$TEMP については、デフォルトの Windows は、でも「アホ」だと思う。「最近の」Unix だと、昔なら自分で書いたりもしてた「ゴミ掃除系 cron タスク」が標準でしのばせてあったりするけれど、伝統的にも「今も」、一時ファイル削除がデフォルトでくっついてきた Windows は、なくないですけ? 少なくともいつ覗いてみても $TEMP は満腹状態になっとるね。(ソフトウェア開発やってると特になのよね。コンパイラ関係が大量の一時ファイルを必要とするので。)

で。Windows だろうが Unix だろうが、実は敵は「大きなファイル」よりも「大量のファイル」なのは同じで。じゃぁどうするか?

答えは「条件付で」簡単で、「細切れにやればいい」だけ。

「条件」とは、要するに「トランザクション保障」とか、「アトミック性」と呼ばれるそれ。「成功するなら完全に成功し、失敗するなら完全に失敗する」言い換えると「状態を完全に変えるか、さもなければ「一切変化させない」」。つまりは「Windows では特に」はこの保障に関係してて。もっと簡単に言えば、「細切れにやっちゃって削除成功したものが一つでもあると、二度と全体をやり直せない」。そ。後には引き返せんとです。

OK?

「細切れにやればいい」のやり方はいくらでもあろう。ここでは Unix シェル的に:

1 me@host: ~$ cd $TEMP  # とか cd /tmp とか
2 me@host: /tmp$ #rm -f *  # これがもう返ってこない
3 me@host: /tmp$ while : ; do ls | head -300 | xargs rm -fv ; done

300ずつ無限ループ。終わったら手動で Ctrl-C でインタラプトする。こんなことをしなければならないほどの量なのだから、これでも結構な時間がかかるであろうが、それでもこれ、猛烈に速い。

わかるかもしれないが、これはデータベースにも言えて、「トランザクション保障が要らない大量削除」が必要な場合、これに似た発想が有効な場合がある。(データベースの方がむつかしいのは、まさにその「本物のトランザクション保障」との格闘になる場合があるから。ま、インデックスやら外部キー制約やら、ほかにも頭痛の種はあろうけどさ。)

なんでこんなネタか、というと。

なんか、cython ビルドを何百回もしいの、svn、Mercurial 操作を何度もしぃの、WinMerge で何度も確認しぃの、ってやってたら、気付いたら /tmp に万近くファイルが出来てたの。そんな状態でね、「.svn以前に、build フォルダが…」で紹介した

1 me@host: ~$ python setup.py build_ext --build-temp=/tmp --build-lib=/tmp

の動作確認しようにも…、埋もれちゃってわからんのぞ。






あとはさ。気付いたら消す、のじゃなく、タスクスケジューラなり、スタートアップなりで毎日とか消すのがいいわいな。

_2015-07-22 22:50投稿

なんだかこの投稿、それなりに需要あるみたいなんだけど、おそらくここに辿り着いちゃった人は、なんだよ、と思ったに違いない、と思うのだね。考え方は伝えてるけど、答えはあんまし書いてないからね。おそらくこのネタに喰い付く人は、いわゆる技術者ではないんだと思う。なおかつ、おそらく Windows ユーザが多い。とするならば、「Unix的に」なんてもう意味わからん可能性が高いし、ましてや「Windows で Unix もどき環境を使う」はもっと意味わからんでしょう。

なんにも事前準備なく Windows でこれをやる方法、となれば、いまは PowerShell がいいんだと思う。PowerShell搭載バージョンについて前に書いた通りで、「Windows = DOS」なんてパブロフの犬じゃあるまいし

てわけで、PowerShell でやってみた。馬鹿みたいに時代遅れで危険な Windows を大事にしてない限りは、あなた、既に PowerShell 持ってるんだよ、てことね。

ただし。「細切れに」なんだけどね、これは特殊なことしなくて大丈夫です。だいたいこんな感じ:

1 PS C:\Users\hhsprings> cd $(Get-ChildItem env:temp).Value
2 PS C:\Users\hhsprings\AppData\Local\Temp> Remove-Item -Recurse $(dir)

PowerShellコンソールの起動の仕方についてはこことかみてね

実は4月の投稿では少し説明を誤魔化したんだけどね、

1 me@host: ~$ cd $TEMP  # とか cd /tmp とか
2 me@host: /tmp$ #rm -f *  # これがもう返ってこない

が「これが返ってこない」のは、いつ誰がそれを評価するのか、に関係しててね。言うまでもなく「*」はシェルが解析(展開)後に rm コマンドに渡されるのです。だから大量ファイルで膨大な時間がかかる。4月の説明はアトミック保障の話だけしたけど、実際にはこれも時間がかかる要因なのね。PowerShell の上記は、一万のファイルでも数秒で終わりますが、これが速いのも、評価の順番の関係。

ところで、最初の投稿時点でのものは、MSYS使ったんだけどね、ワタシ。いやはや、こっちの PowerShell 版の方が圧倒的に速いわ。(ただね、こんなん毎日やるもんではないからさ、「3時間かかっても終わらない」よりは爆速、ならそれでいいのですよ。だからやり方にはこだわらなくていいんです。実際そういう困り方でこんな検索するんでしょう?)