rm
コマンドを使っていてなんか時間がかかるな、と思ったら
変数が空だったり($a/$b
→/
)、
引数の中に無駄なスペースがあったり(~/*.log
→~/* .log
)して
うっかり重要なファイルやディレクトリを
rm
してしまうことは1度や2度は経験していると思います。
最近下の参照先の流れを見て、最初は自分のゴミ箱スクリプト
を
もうちょっとマシにアップデートしよう、と思ったのですが、
rm
関連の事でも調べたら改めて知ったこともいくつかあったので
その辺をまとめておこうと思います。
基本的にbash
での話です。
rmコマンドを安全にする
rm -i
rm
に-i
オプションを加えると消去する時に1つ1つ消すかどうか確認しながら
消せる様になるわけですが、通常デフォルトでは確認する様になっていないので、
上記リンクの2番めにもある様に、
alias rm="rm -i"
などと.bashrc
等に書いておけば-f
を与えない限り確認する様に出来ます。
ただ、後から-f
を与えればそれが優先されるので、同記事内にあるような
rm -rf ~/
は防げません。これを防ぎたいなら
function rm { command rm $@ -i;}
の様に関数でラッパーを作ってやれば常に-i
を有効に出来ます。
逆に、この様にしてしまうと-f
を与えても意味が無いので、
確認無しで消すには/bin/rm a
やcommand rm a
などとして
元のrm
を直接呼び出す必要があります。
rm –preserve-root
--preserve-root
オプションは/
を引数として使用できなくします。
参照
これは環境にようってデフォルトでそうなっていたり そうでなかったりするみたいです。
root
状態やsudo
でのみ関係あるところなので、
コマンドラインから作業する時はこれ抜きでも慎重になるべきですが、
結構簡単なことでも、
rm -rf $abc/$def
としたつもりが
rm -rf $abv/$deg
等タイポしたりそもそも変数が空(未定義)だったりすると大変な事になるので、 これくらいはaliasに(rootのものにも)入れておいても(デフォルトでなければ) 良いかと思います。
set -u
未定義変数を絶対に使わない、と言う状況であれば
set -u
をしておくと、タイポで未定義の変数を使おうとした時に
エラーを吐く様になるので、rootで限られた作業しかしない場合や
そこで使うスクリプト内ではset -u
をしておくと安全です。
${VAR:?}
set -u
だと、もし$abc
が一時的に空文字になる可能性がある時は
それを検出することは出来ません。
また、シェルスクリプトの特性上、敢えて変数が未定義な状態と空文字な状態と
同等に扱ってコードを書いている事もあるので
set -u
はあまり良い選択肢ではないかもしれません。
(逆にその辺をきちんと考えてset -u
しても問題ないコードの方が安全だ、という
人もいるかもしれませんが。)
いずれにせよset -u
だとまだ危ない部分がありますが、
これを避けるためには
rm -rf ${abc:?}/$def
としておくとabc
が未定義もしくは空文字の時にエラーになりそこで終了します。
これであればset -u
と違いrm -rf
に関する部分だけ
のチェックになりますし定義済みの空文字にも対応できます。
ホームをプロテクトする1
寸前にcd
してしまい気づかないままふとrm -rf *
をしてしまったり、
上の場合同様変数が空だったり、引数を書いてる途中でスペースが
入ってしまって*
や~
が独立してしまって間違って展開されて
恐ろしい事になったことは、誰しもが経験し得ることかと思います。
Linuxを初めて使い始めた頃に、1回やりかけて恐ろしくなって プロテクトするようなラッパーを使っていました。 冗長過ぎる感が強かったので、結局すぐに消してしまって どんなだったか覚えてなかったのですが、 改めて書いてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
ホームディレクトリそのものを消そうとした時や
ホームディレクトリ下にあるディレクトリを消そうとした時に
rm
コマンドの前に別に1回確認を取ってくれる様に
しています。
といくつか簡単にrmにラッパーをかける方法を書きましたが、
特に最初の2つの様な-i
を要求する変更は
スクリプト内で、.bashrc
等設定を読み込んだ状態で
rm
を素のまま使っていると、
スクリプトがそこで止まるので、cron
ジョブで使ってるものなど
影響が出る可能性があるので気をつけてください。
最後の物は全ての引数をチェックしているので 引数が多いと結構邪魔くさいです。
(現在は上の様な設定はせずにrm
は素のrm
のまま使っています。)
ホームをプロテクトする2
ホームでのrm -rf *
を予防する方法としてホームで見える
ファイルやディレクトリを全てシンボリックリンクにしてしまう、
と言う方法もあります。
~/usr
という様なディレクトリがある場合、~/.usr
や~/.home/usr
と言った.
で始まるディレクトリ内に
実体を作ってホームにはそこからシンボリックリンクを貼っておくと、
消されるファイルはシンボリックリンクだけなので被害を
最小限に抑えられます。
$ cd ~
$ mkdir ./.home
$ mv ./usr ./.home/usr
$ ln -s ./.home/usr ./usr
この方法ではrm -rf ~/
とディレクトリを指定された場合は防げませんが、
rm
コマンド自体はそのままなので他への影響を
最小限に抑えられます。
ただ、環境によっては$HOME
に沢山シンボリックリンクがあると
余計な負荷をかける事もあるので注意して下さい。
その他見つけたもの
上でやっているような事も含めて色々な物がweb上に転がっていると思いますが、
今回ちょっと調べてるうちに、
割とよさそうなものとしてsafe-rm: http://www.safe-rm.org.nz/
というものを見つけました。
perlで書かれていて、消したくないディレクトリを指定しておいて 消せないようにする、と言うものですが、 設定ファイルに書くことで簡単にディレクトリが追加出来るのが 良い感じです。
コマンドラインでゴミ箱を使う
以上は直接ファイルやディレクトリを消してしまう
rm
をする時に如何に気をつけるか、という話でした。
一方で、パソコンを使い始めて凄い便利だな、と思うことの1つに
当たり前のことですが簡単に元に戻す
事が出来る事があると思います。
(もうちょい前から始めてる人はそれは当たり前のことではない、と言うかもしれませんが…)
ゴミ箱に捨てても後から簡単に戻す事が出来る事もその1つ。
その様なゴミ箱に慣れてる状態で、初めて黒い画面でrm
を使うと
そのファイルが簡単に元に戻せない、ということに軽く恐怖を覚えます。
そういう物だと慣れれば、rm
コマンドを使う時に
ちゃんと考えてから消すようになるわけですが、
今でもたまにちょっとしたファイルを消して暫くした後に
消したファイルを確認出来れば便利だな、と思うことがあります。
そこで、これまではファイルを消す代わりに 適当なゴミ箱ディレクトリに移す簡単なスクリプトや関数を 使っていました。
今回、アップデートしてコマンドラインから元に戻せる様にもしたので 載せておきます。
trash.sh
インストール
スクリプトはGitHubにあります:
wget https://raw.github.com/rcmdnk/trash/master/bin/trash
するか、trashフォルダ毎
git clone [email protected]:rcmdnk/trash.git
してスクリプトbin/trash
を取ってください。
インストールはこのスクリプトを適当なPATHの通ったディレクトリに入れるなり aliasで使える様にしてください。
自分の環境ではcloneしたディレクトリから~/usr/bin
(PATHが通っている)
にリンクを張り(リンク先では.sh
は除いてます)、
.bashrc
内でalias del="trash"
としています。
(元からスクリプト名をdelにしても良いわけですがなんとなく…)
rmを変更しても良いと思いますが、上にも書いたようにあまり rm自体を変更するのは好きではないので別コマンドにしています。
使い方
rm
と同じ様なオプションを使える様にしてあります。
詳しくはtrash.sh -h
やスクリプトを御覧ください。
例1:
$ cd tmp/
$ ls
$ touch a
$ trash.sh a
~/tmp/a was moved to ~/.Trash/my_trash_box/20130423/a
$ touch a
$ trash.sh a
~/tmp/a was moved to ~/.Trash/my_trash_box/20130423/a.1
$ ls
$ trash.sh -b
2 20130423-03-24-29,~/tmp/a
1 20130423-03-24-37,~/tmp/a
choose trash number: 1
~/tmp/a was restored from ~/.Trash/my_trash_box/20130423/a.1
$ ls
a
$ trash.sh -l
1 20130423-03-24-29,~/tmp/a
$
消去するファイルはゴミ箱(~/.Trash/my_trash_box
)下の
日付ごとのディレクトリに移動されます。
もし、同じファイル名の物が削除されると、数字を付けて区別します。
-b
オプションを使うことで一覧を表示させ、その中から
番号を選択することで該当物を元に戻すことが出来ます。
-l
オプションは削除物をリストするだけのコマンドです。
これ以外に-r
(ディレクトリ削除)、-f
(確認しない、デフォルト)、
-i
(確認を行う)というrm
同様のオプションがあります。
また、trash.sh -c
とすると、下のオプションで設定する
ゴミ箱容量を超えた分を古い物から消していきます。
ゴミ箱ディレクトリを自動的に削除されないディレクトリに指定している場合、
cronなどでtrash.sh -c
を定期的に行う様にしてください。
Macの~/.Trash
に指定したり、/tmp
以下に作る様な場合は
余程大きな容量に指定しない以上は必要無いかもしれません。
trash.sh -C
(大文字のC
)とすると、ゴミ箱を全て空にします。
注意として、この様に直接ゴミ箱内に移動されたものは
Finderからゴミ箱を開いた場合も表示されますが、
Finderから元に戻す事はできません。
右クリックしても元に戻す
の項目はでません。
Finderから直接他へ移動させる事は可能ですが、
コマンドラインからtrash.sh
を使えば簡単に元に戻せます。
オプション
設定変数は以下の通りです。適時.bashrc
などで設定してください。
変数 | 説明 |
---|---|
TRASHLIST | ゴミ箱に移動したファイル/ディレクトリのリスト用ファイル。デフォルトは~/.trashlist 。 |
TRASHBOX | ゴミ箱親ディレクトリ。デフォルトは~/.Trash (Macの通常のゴミ箱ディレクトリ)。このディレクトリの下にmy_trash_box というディレクトリを作り、さらに日毎のディレクトリを作りその下に削除された物が移動される。 |
MAXTRASHBOXSIZE | ゴミ箱の容量(MB)。デフォルトは1024。この容量を超えた状態でクリーンアップコマンドを使うとこの容量以下になるように古い順にゴミが削除される。 |
MAXTRASHSIZE | このサイズを超えるファイル/フォルダは直接rm で削除する。 |
デフォルトの設定にあるように、ゴミ箱の容量は比較的小さめ(1GB)
に設定してあります。
さらに~100MBを超える様なファイルの場合には直接rm
する様に設定しています。
基本的にはrm
を使い、
ちょっとした設定ファイルやスクリプトなど、取り敢えず要らないけど
もしかしたら後で見るかも、と思うな物を上で書いたalias del
を使って
削除する、と言った形を取っています。
その辺りは好み次第かと。
webで見つけられるその他のゴミ箱実装
Mac, AppleScriptを使った方法
OSX - mv2trashというスクリプト書いた
にあるように、MacではAppleScriptの力を借りると
通常のゴミ箱に捨てる
作業と同じ様にコマンドラインで
削除することが出来る様になります。
コマンドラインからゴミ箱に捨てるシェルスクリプトにはシェルスクリプトを使って書いているものがありました。
Macの場合は上の
trash
に削除部分でmv
の代わりに使っても良いかな、
とも思ったのですが、2つ目の参照先にもある様にかなり遅くなるので、
頻繁に使うには余り実用的で無い感じがしました。
Mac, rmtrash
mac用の他のものとして、rmtrash という物を良く見かけました。
HomebrewやMacPortsでインストール出来るところから
多少良く出回っている感じがしますが、単に.Trash
に
送っているだけです。
もしかしたら古いバージョンを見ただけなのかも知れませんが、
確認した所、上の
trash
同様、単にゴミ箱フォルダに移動させてる
だけのようなので(sourceを見る限りでも)、
捨てられたファイルはFinderから直接見ると
元に戻す
、は使えませんでしたし、rmtrash
自体に
戻す機能が無いので元の場所の情報は残ってないことになります。
(Obj-cまで使ってやる必要が良くわかりませんでした…)
trash-cli
trash-cliは pythonベースでゴミ箱を実装したパッケージです。 pythonの環境(python 2.7)を整えればどのOSでも基本的には 使えます。
このパッケージには、ゴミ箱から元に戻したりゴミ箱を 空にしたりするコマンドも入っています。
nrm
自分で試してないですが、 nrmといったものも有りました。
rm tips
消せないファイルを消す方法
手違いで記号から始まる様なファイルを作ってしまったり、
文字化けしてしまう様なファイルを消したい場合、
"
などで囲ってみてもどうしても上手く行かない場合があります。
この様なファイルを消す手っ取り早い方法は、必要なファイルや ディレクトリを他のディレクトリに移し、 そのファイルを含むディレクトリ毎消してしまうことです。
さらに安易な方法は、MacならFinder等、GUIファイルマネージャー を開けば大概の場合消去出来ます。
まじめに削除しようとする場合には、 inodeを使って消します。
$ ls -i
45323032 a
とするディレクトリ内にあるファイル/ディレクトリのinode番号が分かるので、
(上の場合はa
と言うファイルだけあり、inode番号が45323032
)
この番号を用いて
find . -inum 45323032 -exec rm -rf {} \;
とすれば目的のファイル/ディレクトリを確実に消せます。
消してしまったファイルの復旧
rm
で消してしまった場合でも、ゴミ箱を空にしてしまった場合でも、
これらの消す
作業は基本的に情報を保持したブロックとの
リンクを切ってその部分を使える様にする(余り正確な記述じゃないかもしれませんが)
という作業なので、そのブロック自体には
上書きされるまで情報が残っている可能性があります。
この様な時は、すぐにそのディスク自体への書き込みを禁止にして 復旧作業を行えば情報を復旧出来る事があります。
デジカメなんかで間違えてSDカード内全消去、とかしてしまったとか言う 場面に何度か合いましたが、WindowsにもMacにも 無料のサルベージソフト(または期間限定で無料で使えるソフト) が沢山あるので、適当な物を ダウンロードしてきて毎回比較的簡単に復旧出来ています。
Linux等でext4
を使っている場合はextundeleteというユーティリティがあり、
Linuxでうっかりrm -rfしちゃったけど復活出来たよー\(^o^)/が参考になります。
まとめ
rm
のプロテクトやゴミ箱、さらに復旧についてまで見てみましたが、
結局のところ、バックアップさえしっかり取っておけばなんとかなるので、
重要なな部分については最低1日1回はバックアップが取れる様な
体制をとっておきたいところです。
今回は特にファイル削除に関することなので、上記のスクリプトも含め、 ご利用は計画的に。
trash は手元のMacとWindowsのcygwin、Red Had系のLinuxで試していますが、 不具合やもっと良く出来そうな部分があれば教えて頂けると嬉しいです。
最後に、rm -rf /
をやってみました動画をどうぞ。
Ref:
僕がMacのホームディレクトリを削除するに至った経緯と、復元するまでの道のり- 私みたいなおっちょこちょいを自滅から救って来たちょいとした工夫x3+1
-
[dankogai/osx-mv2trash: mv2trash - move (file folder)s? to trash on OS X](https://github.com/dankogai/osx-mv2trash)