我想访问 zsh 历史记录,其中的条目用 分隔,\0
而不是\n
。内置解析器可以清楚地处理多行条目,因为fc 123
会打开一个保留换行符的编辑器。但是,fc -l 123
(打印到标准输出而不是启动编辑器)将换行符转换为等效的\\n
.这意味着历史记录中包含该文字的任何命令都\n
无法与换行符消除歧义(例如,printf "\n"
在 awk 调用中)。
有没有办法使用zshfc
或history
zsh 中的内置函数来获取未更改的历史记录条目?我试图避免编写历史文件解析器的工作。作为参考,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>