ファイル削除のために使う、みんな大好き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