从 shell history 中排除无效命令

实时过滤 .bash/zsh_history 中误输入的无效命令,让历史记录更加简洁,便于查找

众所周知,在 Linux shell 中执行过的命令通常会被自动保存至当前用户目录下的 .bash_history / .zsh_history 等文件中,可以通过 history 命令查看。命令历史记录对于许多依赖历史命令进行分析和自动补全的 shell 插件是相当重要的。

实际使用过程中,手工键入的命令难免会出现错误,比如偶然打错了命令中的某个字母,导致 command not found。这部分错误的命令就成了命令历史记录中的“脏数据”。我们希望能有一种过滤机制,将这些无效命令从历史记录中剔除。

一种简洁高效的实现方案是:在任意一条命令执行完毕后,读取其返回值,判断命令是否有效(exit status 127 表示 command not found),若无效则将其从历史记录中删除。

我检索了互联网上的相关信息,中文社区内暂时不存在这方面的内容,英文社区内可以找到这样的一篇文章:Avoiding invalid commands in Bash history | boltblog,利用 bash 读取 PROMPT_COMMAND 环境变量的机制实现了上述功能。如果只使用 bash,只需照搬文中的命令放入 ~/.bashrc 中即可。

但是我发现,这个脚本对于 zsh 并不生效,一是因为 zsh 并不会在每个交互提示信息出现之前执行 ${PROMPT_COMMAND} 中的指令,而是提供了precmd 函数来实现类似的功能;二是 zsh 内建的 history 命令与 bash 有一定差异,比如它不支持通过 history -d 删除单条命令历史记录,而需要使用 fc 命令手动操作历史记录文件(参考 stackexchange)。

鉴于 ${ZSH_VERSION} (${BASH_VERSION}) 变量定义与否可以用于判断当前所处的 shell 类型,我将 bash 和 zsh 两种 shell 下实现无效命令历史记录过滤的方案整合为一段脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[ ${BASH_VERSION} ] && PROMPT_COMMAND="mypromptcommand"
[ ${ZSH_VERSION} ] && precmd() { mypromptcommand; }
function mypromptcommand {
    local exit_status=$?
    if [ ${ZSH_VERSION} ]; then
        local number=$(history -1 | awk '{print $1}')
    elif [ ${BASH_VERSION} ]; then
        local number=$(history 1 | awk '{print $1}')
    fi
    # echo $number
    if [ -n "$number" ]; then
        # If the exit status was 127, the command was not found. Let's remove it from history
        if [ $exit_status -eq 127 ] && ([ -z $HISTLASTENTRY ] || [ $HISTLASTENTRY -lt $number ]); then
            local RED='\033[0;31m'
            local NC='\033[0m'
            if [ ${ZSH_VERSION} ]; then
                local HISTORY_IGNORE="${(b)$(fc -ln $number $number)}"
                fc -W
                fc -p $HISTFILE $HISTSIZE $SAVEHIST
            elif [ ${BASH_VERSION} ]; then
                local HISTORY_IGNORE=$(history 1 | awk '{print $2}')
                history -d $number
            fi
            echo -e "${RED}Deleted '$HISTORY_IGNORE' from history.${NC}"
        else
            HISTLASTENTRY=$number
        fi
    fi
}

只需要将上面的代码放入 ~/.bashrc~/.zshrc 并重启 shell 即可生效。若上一步执行的命令 cmd 无效(not found),shell 将以红色字体提示 Deleted 'cmd' from history.

-------------本文结束    感谢您的阅读-------------
0%