导出 zsh 历史记录,以“\0”字符而不是“\n”分隔

导出 zsh 历史记录,以“\0”字符而不是“\n”分隔

我想访问 zsh 历史记录,其中的条目用 分隔,\0而不是\n。内置解析器可以清楚地处理多行条目,因为fc 123会打开一个保留换行符的编辑器。但是,fc -l 123(打印到标准输出而不是启动编辑器)将换行符转换为等效的\\n.这意味着历史记录中包含该文字的任何命令都\n无法与换行符消除歧义(例如,printf "\n"在 awk 调用中)。

有没有办法使用zshfchistoryzsh 中的内置函数来获取未更改的历史记录条目?我试图避免编写历史文件解析器的工作。作为参考,fish 有history -z此用例。

(奖励:我也想做同样的事情来分析 bash 历史记录。它的fc行为似乎与 zsh 不同。)

答案1

使用history变量和参数扩展(可能包括(关联)数组索引) 特征。

例如,原始等效项fc -l 123 123$history[123]。要获取数组中的一系列历史元素,可以使用${(v)history[(I)<123-456>]}.要获取字符串中以 null 分隔的历史元素列表,您可以使用${(vpj[\0])history[(I)<123-456>]}. (但请注意,历史记录元素可以包含空字节,并且您不能将空字节传递给外部命令,因此这不是特别有用。)

打印对于那些 NUL 分隔的,您还可以使用print -N, 结合-r使用来禁用反斜杠扩展,-C1因此如果没有匹配项,它不会打印任何内容:

print -rNC1 -- ${(v)history[(I)<123-456>]} | fzf --read0

或者:

print -rNC1 -- $history | fzf --read0

以整个历史为例。

答案2

对于bash,如果我们假设您输入的命令的第二行和后续行不以空格、数字和至少 2 个空格开头,您可以执行以下操作:

HISTTIMEFORMAT= history | LC_ALL=C gawk -v RS='\n *[0-9]+  ' -v ORS='\0' '
  NR==1 {sub(/^ *[0-9]+  /, "")}
  {print}'

要转换历史输出(删除时间戳),如下所示:

  123  cmd
  124  echo 'multiline
command'
  125  ...

到:

cmd<NUL>echo 'multiline
command'<NUL>...<NUL>

相关内容