tkuchikiの日記

新ブログ https://blog.tkuchiki.net

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 して順番を揃えたほうが良さそうです。

tkuchiki.hatenablog.com

では、CentOS6 だとだめでしたが、これを応用すると CentOS6 でも HISTFILE にコマンドの履歴を残しつつ、history を消すことができました。
zsh には preexec hook という機能があるそうなので、trap ではなくそちらを使うと良いようです。

この設定が安全かどうかは確認できていないのでご利用の際はご注意ください(使う人いないと思いますが)。

参考