
ファイル削除のために使う、みんな大好きrmコマンド。これの安全対策を取りました。
筆者が使用しているmacOS環境での動作を前提にしています。
rmは危険
rmは基礎中の基礎コマンドですが、「ゴミ箱へ送る」のとはちがい、ほんとうにファイルが削除されてしまいます。
ファイルをgit管理するなど、バックアップを取っていれば復旧は可能ですが、悲劇はそういったバックアップがないときに発生するものです。新規作成したばかりでgit addする前のファイルとかね。
手が滑ってrmして消してしまうことを防ぐため、筆者は以下のようなエイリアスを設定し、確認を挟むようにしていました。
alias rm='rm -i --preserve-root'
しかし、削除したいときは削除したいのだから、確認が挟まるのはめんどくさいものです。気づけば手癖のようにrm -fを入力し、毎回確認をバイパスしていました。これは危険。
rmは危険だから代替を使う
macOS 14でtrashコマンドが導入されました。これは要するに「ゴミ箱へ送る」コマンドです。一旦trashしたものもシステムのゴミ箱ディレクトリから復旧できるので、間違って消したとしてもなんとかなります。
`man trash`
TRASH(8) System Manager's Manual TRASH(8)
NAME
trash — Moves files and directories to the user
trash folder
SYNOPSIS
trash [-h] [--help] [-s] [-stopOnError] [-v]
[--verbose] FILE [FILE...]
DESCRIPTION
The trash moves files and directories into the user
trash folder. The options are as follows:
-h | --help
display usage information for the tool
and exit
-v | --verbose
display more verbose status
-s | --stopOnError
exit with an error if any move to a
trash folder fails
EXAMPLES
In a directory with a file named "Foo.txt" and a
directory "Bar",
trash Foo.txt Bar
moves the file and directory into the user's trash
folder, if it exists and permissions allow the
items to be moved into the user's trash folder.
HISTORY
First appeared in macOS 14.0
macOS May 25, 2022 TRASH(8)
これをrmの代わりに使うようにすればよいでしょう。
エイリアスすれば一見一件落着ですが…
シェル設定が何らかの理由で読み込まれなかったり、異なる環境に入ったりと、エイリアスのない環境で作業する可能性はあります。そういった状態で「いつものtrash」のつもりでrmしてしまうと危険です。
rmは危険だから代替を使うように矯正したい
エイリアスに頼ると、エイリアスが設定されていないときに事故が起きる危険がある…。したがってそもそもrmを入力せずtrashを使うように人間のほうを矯正したほうがよいでしょう。エイリアスを使うならこうするべきです。
alias rm="echo 'rm is dangerous command! Use trash instead'"
これでrmを使おうとすると怒られるようになります。都度怒られていれば、そのうち自然とtrashを使うように矯正できるでしょう。
とはいえ、たまに明らかに消して良いファイルやディレクトリもあります。筆者の感覚では、macの.DS_Storeや、nodeプロジェクトのnode_modulesなどが該当します。この辺は消しても困らないし、必要になれば自動ないし手動で生成されます。
rmは危険だから代替を使うように矯正したいけど明らかに消して良いファイルに対してはrmを使いたい
安全のためにtrashを使うようにしたいけど、「このファイルはノーチェックで消して良いな」と事前にわかっているファイルに対してはrmを使ってサクッと消したい。
ということで以下のスクリプトを作成しました。rmという名前で保存し、実行権限をつけ、実際のrmコマンドより優先されるようにパスを通しておきます 。
my-bin/rm
#!/usr/bin/env bash
rm_abort() {
echo "'rm' is dangerous command! Use 'trash' instead"
exit 1
}
declare -A safe_files=(
[".DS_Store"]=1
["node_modules"]=1
)
args=()
for arg in "$@"; do
[[ "$arg" != -* ]] && args+=("$arg")
done
if [[ ${#args[@]} -eq 0 ]]; then
rm_abort
fi
for arg in "${args[@]}"; do
base=$(basename "$arg")
if [[ -z "${safe_files[$base]}" ]]; then
rm_abort
fi
done
/Users/kawarimidoll/.nix-profile/bin/rm -i --preserve-root "$@"
筆者はnix home-managerを使ってcoreutilsを入れているので/Users/kawarimidoll/.nix-profile/bin/rmを呼び出していますが、各々の環境に合わせてパスを変えてください。
また、ファイル名はbasenameを使って対象の末尾のみで判定しています。長いパスを認識したい場合は修正が必要です。
設定したら、which rm where rmを実行し、このファイルが最優先で実行されるようになっていることを確認しておきましょう。ふつうのrmのほうが優先されていたら意味がないので。
Views: 0
