如何从 zsh 历史记录中删除最后一个命令(或当前命令以获得奖励)

如何从 zsh 历史记录中删除最后一个命令(或当前命令以获得奖励)

当然有一个超级简单的智能方法可以做到这一点,但是由于 zshell 中的历史记录似乎是 fc 的别名,因此无法使用中提到的技巧如何从历史记录中删除一行?

有关如何执行此操作的任何指示?我的用例是从历史记录中删除最后发出的命令,以便它停止自动完成(主要是当您输入错误的内容并且它不断显示时)。

我知道我可以通过执行以下操作来获取最后发出的命令

history | tail -n 1,但 History -d 不起作用,我找不到 zsh 的正确文档。

答案1

Zsh 不提供真正的历史编辑功能。命令历史记录基本上是只读的。您所能做的就是批发更换它。

编辑命令历史记录:

  1. 将其保存到文件中:fc -W
  2. 编辑文件
  3. 从文件加载历史记录:fc -R

您可以通过设置来选择文件名HISTFILE

未经测试的代码:

remove_last_history_entry () {
  setopt local_options extended_history no_hist_save_no_dups err_return
  
  local HISTFILE=~/.zsh_history_tmp_$$ SAVEHIST=$HISTSIZE
  fc -W
  ed -s $HISTFILE <<EOF >/dev/null
d
w
q
EOF
  fc -R
}

答案2

通常您可以从 中删除该行~/.zsh_history,但如果找不到它,请查找~/.zshrc历史文件的位置。

然后使用您选择的任何文本编辑器删除有问题的行。或者,只需删除整个文件并关闭所有 zsh 实例并启动一个新实例。历史被清除!

答案3

是的,这是一个老话题,但是这些问题都没有回答我的问题,所以我花了很长时间试图弄清楚这一点!

这是我的解决方案,感谢@Gilles有关使用“fc -R”和“fc -W”的提示:)。

将下面的脚本粘贴到您的 .zshrc 文件中。

使用源 .zshrc 重新加载

然后输入“forget”忘记最后一个命令:D。输入“forget 3”即可忘记最后 3 个命令。一些性感的嘶嘶声。

按向上箭头将直接带您到最后一个命令,并且也不会记住“忘记”这个词:)。

更新:添加了主路径,因此它现在可以在所有目录中使用,哈哈。

更新2:添加了传递您想忘记的最后命令数量的功能:D。尝试“忘记 2”来忘记最后 2 个命令:D。

# Put a space at the start of a command to make sure it doesn't get added to the history.
setopt histignorespace

alias forget=' my_remove_last_history_entry' # Added a space in 'my_remove_last_history_entry' so that zsh forgets the 'forget' command :).

# ZSH's history is different from bash,
# so here's my fucntion to remove
# the last item from history.
my_remove_last_history_entry() {
    # This sub-function checks if the argument passed is a number.
    # Thanks to @yabt on stackoverflow for this :).
    is_int() ( return $(test "$@" -eq "$@" > /dev/null 2>&1); )

    # Set history file's location
    history_file="${HOME}/.zsh_history"
    history_temp_file="${history_file}.tmp"
    line_cout=$(wc -l $history_file)

    # Check if the user passed a number,
    # so we can delete x lines from history.
    lines_to_remove=1
    if [ $# -eq 0 ]; then
        # No arguments supplied, so set to one.
        lines_to_remove=1
    else
        # An argument passed. Check if it's a number.
        if $(is_int "${1}"); then
            lines_to_remove="$1"
        else
            echo "Unknown argument passed. Exiting..."
            return
        fi
    fi

    # Make the number negative, since head -n needs to be negative.
    lines_to_remove="-${lines_to_remove}"

    fc -W # write current shell's history to the history file.

    # Get the files contents minus the last entry(head -n -1 does that)
    #cat $history_file | head -n -1 &> $history_temp_file
    cat $history_file | head -n "${lines_to_remove}" &> $history_temp_file
    mv "$history_temp_file" "$history_file"

    fc -R # read history file.
}

所以这里发生了一些事情。该命令将允许我们在任何命令之前键入一个空格,并且它不会添加到历史记录中。

setopt histignorespace

因此,我们可以按空格键,然后输入“echo hi”,按 Enter 键,当我们按向上箭头时,“echo hi”不在我们的历史记录中:)。

请注意别名“forget”在 my_remove_last_history_entry 之前有一个空格。这样 zsh 就不会将我们的“忘记”保存到历史中。

函数解释

ZSH 使用 fc 来记录历史记录或其他内容,因此我们使用“fc -W”将当前命令写入历史文件,然后使用“head -n -1”从文件中删除最后一个命令。我们将该输出保存到临时文件中,然后用临时文件替换原始历史文件。最后使用 fc -R 重新加载历史记录。

然而,该函数存在一个问题,该问题已通过别名修复。

如果我们按函数名称运行该函数,它将删除最后一个命令,即对该函数的调用。这就是为什么我们使用别名并使用空格调用它,这样 zsh 就不会将此函数名称添加到历史文件中,从而使最后一个条目成为我们想要的条目:D。

答案4

我使用 @pandagoespoop 的简化版本 回答,它对我来说工作得很好(限制:在linux上,对于单行命令)。

一项重要的修改是限制新创建的历史文件的权限。重定向到新文件使用默认权限,这将允许组+其他人读取您的历史记录。因此我补充道:

chmod 600 $history_temp_file

完整代码:

setopt hist_ignore_space

alias forget=" forget_last_history_entry"
forget_last_history_entry() {
    history_file="${HISTFILE:-${HOME}/.zsh_history}"
    history_temp_file="${history_file}.tmp"

    fc -W # write current shell's history to the history file.

    # Get the files contents minus the last entry(head -n -1 does that)
    head -n -1 $history_file > $history_temp_file
    chmod 600 $history_temp_file
    mv "$history_temp_file" "$history_file"

    fc -R # read history file.
}

如果我有这样的声誉,我会发表评论。

相关内容