- Published on
Bashでrm -rf *コマンドが実行される前に警告するプロンプトを実装する
- Authors
- Name
- Shou Arisaka nyapp.buzz/shou
- short bio
- Z世代の情報技術者。Next.jsで自作SNSを個人開発中。
Linuxパソコン・サーバーのBashプログラミング言語(スクリプティング言語)上のコマンドラインにおいて、"rm -rf *"`コマンドが実行される前に警告するプロンプトを実装する方法について紹介します。
Linuxコマンドrm -rf
は最も危険なコマンドのひとつとして名高いですね。近年ではサーバー管理者が意図せずこのコマンドを実行してしまい全データを消してしまったという話も聞いたことがあります。
今回はそんなrm -rf
コマンドの危険性を少しでも下げることができたらという思いつきから書いたコードを紹介します。
使用例
$ tmpdird # 新規ディレクトリへ移動
$ ls
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
$ genfiles 3 # ファイルを生成
$ ls
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
8444249304069546 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 3.txt
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
51509920740553578 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 2.txt
36310271996515302 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 1.txt
$ rm -rf * # 全ファイルを削除 > 確認プロンプト > n
W: It seems You are attempting to run kind of dangerous command. Continue? [y/n]
n
$ ls # ファイルが消されていないことを確認
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
8444249304069546 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 3.txt
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
51509920740553578 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 2.txt
36310271996515302 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 1.txt
$ rm -rf * # 全ファイルを削除 > 確認プロンプト > y
W: It seems You are attempting to run kind of dangerous command. Continue? [y/n]
y
$ ls # ファイルが消されてることを確認
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
上記のような具合に、rm -rf *
を実行しようとすると、実行される前に警告を行うプロンプトをします。y
で実行をし、n
で実行をキャンセルします。
コード
ok(){
: <<< '
yes or no prompt
e.g. printf "The file alredy exist here. Override it? " ; ok && echo y || echo n
'
read -n 1 -r ; [[ $REPLY =~ ^[Yy]$ ]] && { echo ; return 0 ; } || { echo ; return 1 ; }
}
red=
\e[1;31m'
grn=
\e[1;32m'
yel=
\e[1;33m'
blu=
\e[1;34m'
mag=
\e[1;35m'
cyn=
\e[1;36m'
end=
\e[0m'
warn(){
printf "${yel}W: ${*}\n${end}" >&2
}
##
shopt -s extdebug
preexec_invoke_exec () {
[ -n "$COMP_LINE" ] && return # do nothing if completing
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`;
# So that you don't get locked accidentally
if [ "shopt -u extdebug" == "$this_command" ]; then
return 0
fi
# // filtering
# Modify $this_command and then execute it
# eval "${this_command}"
# echo "${this_command}"
if [[ "${this_command}" =~ ^(somethingdangercommand$|somethingdangercommand[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
elif [[ "${this_command}" =~ ^(anotherSomethingdangercommand$|anotherSomethingdangercommand[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
elif [[ "${this_command}" =~ ^(rm[[:space:]][-rf]{3}$|rm[[:space:]][-rf]{3}[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
else eval "${this_command}"
fi
# // filtering
return 1 # This prevent executing of original command
}
trap 'preexec_invoke_exec' DEBUG
上記コードを${HOME}/.bashrc
へ追記し、試しに未定義のコマンド、somethingdangercommand
コマンドを実行してみてください。未定義のコマンドなので通常だったら未定義ですよというエラーが出るところですが、プロンプトでn
をエンターすることでコマンド自体が実行されないので、エラーが出ずに終了します。
trap 'preexec_invoke_exec' DEBUG
... 毎コマンド実行前にpreexec_invoke_exec()
を実行
elif [[ "\{this_command}" =~ ^(rm[[:space:]][-rf]{3}|rm[[:space:]][-rf]3[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
... 実行されたコマンドがrm -rf
やrm -fr
のとき警告をする
コマンドを実行する前にコマンドが正規表現に一致するかなど、フィルタをし、フィルタにかかった場合に警告をし、それ以外の場合には通常通り渡されたコマンドをeval
している感じですね。
参考
- Linux trap command help and examples
- linux - Modify all bash commands through a program before executing them - Unix & Linux Stack Exchange
結論
rm -rf
の事故はエクスクラメーション展開で起こってしまうことが多いようです。使わない場合は無効化しておくといいですね。
# disable/turn off history expansion `!` altogether
set +H
15歳でWordPressサイトを立ち上げ、ウェブ領域に足を踏み入れる。翌年にはRuby on Railsを用いたマイクロサービス開発に着手し、現在はデジタル庁を支えたNext.jsによるHP作成やSaaS開発のプロジェクトに携わりながら、React.js・Node.js・TypeScriptによるモダンなウェブアプリの個人開発を趣味でも行う。
フロントエンドからバックエンドまで一貫したアジャイルなフルスタック開発を得意とし、ウェブマーケティングや広告デザインも必要に応じて担当、広告運用・SEO対策・データ分析まで行う低コストかつ高品質な顧客体験の提供が好評。
国内外から200万人を超える人々に支えられ、9周年を迎えるITブログ「yuipro」の開発者、デザイナーでありライター。現在ベータ段階の自作SNS「nyapp.buzz」を日本一の国産SNSとするべく奮闘中。