仅在 BASH 历史记录中保留成功的命令

仅在 BASH 历史记录中保留成功的命令

有时我会误解命令的语法:

# mysql -d test
mysql: unknown option '-d'
# echo $?
2

我再试一次并得到正确的结果:

# mysql --database test
Welcome to the MySQL monitor.
mysql >
...

如何防止错误代码不为 0 的第一条命令进入历史记录?

答案1

我不认为你真的想要那样。我通常的工作流程是这样的:

  • 输入命令
  • 运行
  • 注意它失败了
  • 按向上键
  • 编辑命令
  • 再次运行

现在,如果失败的命令没有保存到历史记录中,我就无法轻松地将其修复并再次运行。

答案2

我能想到的唯一方法是使用history -din $PROMPT_COMMAND。这种方法或任何方法的问题在于,无法判断命令是否因错误退出或以非零退出代码成功完成。

$ grep non_existent_string from_file_that_exists
$ echo $?
1

答案3

最好能有最后一个错误的评论来纠正它,但不久之后,它就会变成潜在的令人困惑的垃圾。

我的方法分为两步:存储失败的命令,并在稍后删除它们。

存储失败的命令:

error_handler() {
    FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}

trap error_handler ERR

trap command signalscommand当其中之一signals被“引发”时执行。

$(command),执行command并捕获其输出。

当命令失败时,这段代码会捕获历史数量最后一条命令保存到历史记录中,并将其存储在变量中以供将来删除。

简单,但与HISTCONTROLand一起使用时无法正常工作HISTIGNORE– 当由于其中一个变量而未将命令保存到历史记录中时,保存到历史中的最后命令的历史编号是上一个命令的命令;因此,如果错误的命令没有保存到历史记录中,则先前的命令将被删除。

稍微复杂一点的版本,在这种情况下可以正常工作:

debug_handler() {
    LAST_COMMAND=$BASH_COMMAND;
}

error_handler() {
    local LAST_HISTORY_ENTRY=$(history | tail -1l)

    # if last command is in history (HISTCONTROL, HISTIGNORE)...
    if [ "$LAST_COMMAND" == "$(cut -d ' ' -f 2- <<< $LAST_HISTORY_ENTRY)" ]
    then
        # ...prepend it's history number into FAILED_COMMANDS,
        # marking the command for deletion.
        FAILED_COMMANDS="$(cut -d ' ' -f 1 <<< $LAST_HISTORY_ENTRY) $FAILED_COMMANDS"
    fi
}

trap error_handler ERR
trap debug_handler DEBUG

稍后删除存储的命令:

exit_handler() {
    for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
    do
        history -d $i
    done
    FAILED_COMMANDS=
}

trap exit_handler EXIT

解释:

退出 Bash 时,对于每个唯一的历史记录编号,删除相应的历史记录条目,
然后清除FAILED_COMMANDS以不删除从已删除的命令继承历史记录编号的命令。

如果您确定它FAILED_COMMANDS不会重复,您可以简单地对其进行迭代
(即 write for i in $FAILED_COMMANDS)。但是,如果您希望它不是从最大到最小排序(在本例中始终如此),请替换uniqsort -rnu

历史记录中的编号FAILED_COMMANDS必须是唯一的,并且从大到小排序,因为当您删除条目时,下一个命令的编号会发生变化 - 即。当您发出 时history -d 2,第 3 个条目变为第 2 个条目,第 4 个条目变为第 3 个条目,依此类推。

因此,在使用此代码时,您不能手动调用history -d <n>
wheren小于或等于存储的最大数字FAILED_COMMANDS
并期望代码正常工作。

exit_handler挂接可能是个好主意EXIT,但您也可以提前随时调用它。

相关内容