bash で特定のコマンドを実行前にキャンセルする
DEBUG を trap すれば、コマンド実行前に任意の処理を挟めるということがわかったので、特定のコマンドが入力されたらキャンセルできないか試してみました。
COMMANDS=$(cat <<EOC
rm -rf /tmp/foobar
EOC
)
preexec() {
[ -n "${COMP_LINE}" ] && return
[ "${BASH_COMMAND}" = "${PROMPT_COMMAND}" ] && return
local cmd_history=$(HISTTIMEFORMAT='%F %T%z ' history 1)
#local cmdtime=$(date -d "$(echo ${cmd_history} | perl -lane 'print join(" ", @F[1 .. 2]);')" +%s)
local cmd=$(echo ${cmd_history} | perl -lane 'print join(" ", @F[3 .. $#F]);')
[ "${cmd}" = "" ] && return
cancel "${cmd}"
}
cancel() {
local cmd="${1}"
IFS=$'\n'
for cancel_cmd in $(echo ${COMMANDS}); do
echo $cmd | grep -qs "${cancel_cmd}" && echo "cancelled ${cmd}" && kill -INT 0
done
}
trap - DEBUG
trap 'preexec' DEBUG
上記を .bash_profile か .bashrc に書いておいて以下のようにコマンドを実行すると、
$ mkdir /tmp/foobar $ rm -rf /tmp/foobar cancelled rm -rf /tmp/foobar $ test -d /tmp/foobar $ echo $? 0
mkdir /tmp/foobar は実行できていて、 rm -rf /tmp/foobar はキャンセルできています。
ただし、これだとコマンドの引数の順番が違うとだめになってしまうので、sort して順番を揃えたほうが良さそうです。
では、CentOS6 だとだめでしたが、これを応用すると CentOS6 でも HISTFILE にコマンドの履歴を残しつつ、history を消すことができました。
zsh には preexec hook という機能があるそうなので、trap ではなくそちらを使うと良いようです。
この設定が安全かどうかは確認できていないのでご利用の際はご注意ください(使う人いないと思いますが)。