auientの日常

ノンジャンルで書きたいことを書くブログ

無慈悲なshellから自分を救う工夫(というかクセ)

私みたいなおっちょこちょいを自滅から救って来たちょいとした工夫x3+1
http://blog.livedoor.jp/dankogai/archives/51863725.html

2番目のnoclobberは知らなかったので参考になったけれど、その他の点でツッコミ・思うところがあったので書いてみる。

alias rm='rm -i'はrm -fを救えない

上記の例は、実はこれだけで防ぐことが出来ていた。
tcsh
alias rm 'rm -i'
bash
alias rm='rm -i'

rmやmvに設定することの多いaliasですが、これは間違い。-iと-fオプションは後に指定された方が有効になるので、alias rm="rm -i"としていてもrm -rfを救うことはできません。試してみましょう。

$ alias | grep rm
alias rm='rm -i'
$ mkdir -p foo/bar/baz
$ rm -rf foo  # これで実行されるコマンドは rm -i -rf foo と等価
$ ls foo
ls: foo: No such file or directory  # 消えてるじゃねーか!
$

この通り消えてしまいます。で、-iを後につけるとちゃんと聞いてくれます。

$ mkdir -p foo/bar/baz
$ rm -rf -i foo #あえて -rf の後ろに -i をつけると
examine files in directory foo? n  # ちゃんと聞いてくれた
$ ls foo
bar
$ 

持論ですが、alias rm="rm -i"はお勧めしません。どうでもいいファイルを消すのにいちいち y で応答する手間が増え、無意識に y を押すクセがついてしまいます。本末転倒です。
自分のオススメは、aliasは設定しておかずに、ディレクトリを消すのにもとりあえずは -rf をつけずに実行するようにすることです。
ディレクトリは -r をつけないと消せないのでエラーになりますが、そのタイミングが「本当に消してもいいものか?」を確認する契機になります。確認した上で履歴を一つ戻って -rf をつければよいのです。

$ mkdir -p foo/bar/baz
$ rm foo  # fooを消すよ
rm: foo: is a directory  # ディレクトリだよ、いいの?
$ rm -rf foo  # 問題なし、消す
$ 

同じ発想で、 rm * したいときはまず echo * して * が何に展開されるか確認した上でechoをrmに変える、というクセをつけると悲しい目を見ずに済みます。

変な記号のファイルを消したいときに気をつけるべきこと

元の記事は、何かのバグでできた「~」という名前のディレクトリを消すために

$ rm -rf ~/

を実行したとの件。対策としては

$ rm -rf \~/

とすべきだったとあって、それは間違ってないんだけど、もっと良い方法があります。
それは、カレントディレクトリを含むパスを指定すること。

$ pwd
/Users/nt/tmp
$ ls -l
drwxr-xr-x    2 nt  staff        68 Apr 13 12:58 ~
$ rm ./~/ # ここがポイント
rm: ./~/: is a directory
$ rm -rf ./~/
$ 

「./~」のように指定することで、~ は$HOMEではなく今いるディレクトリの下にあるファイルなんだよ、とshellに伝えることができます。あとは -rf を後からつけるようにすればカンペキです。
まあこの件に関しては、そもそも「~」は $HOME に展開されるんだよという知識がないと気づくのは難しいと思います。なんだっけな、[ がただのゴミファイルだと思って消しちゃったみたいな話もどっかで聞いたし。そういうバッドノウハウのような知識も、環境なり言語なり、何かに習熟する時には重要になるということで。