无法读取Zsh历史记录的时间戳

18

问题:了解以下时间戳的含义

1241036430

位于 ~/.history

: 1241036336:0;vim ~/.zshrc
: 1241036379:0;vim ~/bin/HideTopBar
: 1241036421:0;ls
: 1241036430:0;cat ~/.history
当我拥有

setopt EXTENDED_HISTORY
HISTFILE=~/.history
在.zshrc文件中。
如何读取时间戳?

我很好奇第二个整数(看起来总是为0)是什么。这个数字代表什么? - Steven Lu
6个回答

21

尝试使用 history -d 命令。或者只需输入 history -,然后按下 Control-D 即可获取所有不同的选项:

% history -
-D  -- print elapsed times
-E  -- dd.mm.yyyy format time-stamps
-d  -- print time-stamps
-f  -- mm/dd/yyyy format time-stamps
-i  -- yyyy-mm-dd format time-stamps
-m  -- treat first argument as a pattern
-n  -- suppress line numbers
-r  -- reverse order of the commands

学到了新的东西,Ctrl-D 可以给出所有选项。谢谢! - Buchi
1
你说的“不工作”是指history -d还是history -上的Tab补全?当你尝试时会发生什么? - Nicholas Riley
5
如果这不起作用,请检查history别名是什么(我的是fc -l 1,它将不接受任何其他选项)。 Zsh的history内置调用fc -l,你可以使用上述选项和fc -l -d等选项。 - simont
不起作用并显示:fc: event not found: -d - zygimantus
请确保您输入的是 fc -l(小写字母 L),而不是 fc -1(数字 1)。 - Nicholas Riley

12

您可以使用这个单行命令从zsh邮件列表中的答案中获取可读时间戳的整个历史记录:

perl -lne 'm#: (\d+):\d+;(.+)# && printf "%s :: %s\n",scalar localtime $1,$2' $HISTFILE
我建议将输出导入到分页器中(例如less)以使其更易读。

3

这个名为localtime的简单工具对于读取带时间戳的文件非常有用:

#!/usr/bin/perl
# http://perl.plover.com/classes/mybin/samples/source/localtime

if ($ARGV[0] eq '-f') {
  *show_localtime = \&show_localtime_list;
  shift;
}

if (@ARGV) {
  for (@ARGV) {
    print show_localtime($_), "\n";
  }
} else {
  while (<>) {
    s/^(\d+)/show_localtime($1)/e;
    print;
  }
}


sub show_localtime {
  my $t = shift;
  scalar localtime $t;
}

sub show_localtime_list {
  my $t = shift;
  my @a = localtime $t;
  "@a\n"
}
  • (这里还有一个小的演示

它可以处理很多情况,似乎能够理解秒和毫秒的时间戳等。

$ localtime < ~/.histfile
<snip>
: Sat Sep 17 05:55:17 2016:0;cat localtime

你能否使用该函数来处理其他历史文件,而不仅限于Zsh的历史文件? - Léo Léopold Hertz 준영
是的,它通常只需要工作。它只是查找第一个数字字符串并将其转换为可读日期。 - olejorgenb

3

使用awk转换时间戳

如果您想要读取文件本身并将其与 grep 或其他筛选器一起使用,则需要转换时间戳。

我编写了这个脚本,并将其保存在我的/usr/local/bin中,它适用于bashzshell

脚本uhistory.awk位于/usr/local/bin/uhistory.awk

#!/usr/bin/awk -f
{ 
        if (match($0,/^#/)) # bash
        {
                nlin++
                #adata="@"substr($0,2) 
                #printf("%s ", adata)
                cmdata = "date -d \"@" substr($0,2) "\" +\"%F %H:%M:%S\"" 
                cmdata | getline datado
                close(cmdata)
                printf("%d %s ", nlin, datado)
        }
        else
        if (match($0,/^:/)) # zshell
        {
            nlin++
            split($0, arr, ":|;")
            cmdata = "date -d \"@" substr(arr[2],2) "\" +\"%F %H:%M:%S\"" 
            cmdata | getline datado
            close(cmdata)
            printf("%d : %s ; %ss % ", nlin, datado, arr[3])
            for (i in arr)
            {
                if (i < 4)
                    continue
                printf("%s ", arr[i])
            }
            printf("\n")
        }
        else
        {
            print $0
        }
}

使用方法: 您可以通过筛选器将历史记录进行管道传输。假设对于zsh的历史文件,其格式如下:

:timestamp:duration;commands

没有 uhistory.awk 过滤器时的情况如下:
% head ~/.config/zsh/zhistfile

: 1570482839:0;la
: 1570482839:0;cd zsh
: 1570482839:0;ls
: 1570482839:1;cat verybigaliasfile.txt
: 1570482839:0;alias
: 1570482839:0;ls -la
: 1570482839:0;vi .zshrc
: 1570482839:0;alias

使用uhistory.awk 过滤器,它会显示为:
% head ~/.config/zsh/zhistfile | uhistory.awk | grep alias

4 : 2019-10-07 18:13:59 ; 1s % cat verybigaliasfile.txt
5 : 2019-10-07 18:13:59 ; 0s % alias 
9 : 2019-10-07 18:13:59 ; 0s % alias 

但如果您的使用不涉及处理文件本身,那么您真正需要的只是一个别名。

将此行添加到您的.zsh_aliases或其他用于别名的位置。

alias history='fc -il 1'

或者从fc命令中选择其他选项。请参阅man zshbuiltins以了解更多信息。


更好的方法是使用相同的命令,这样在您想要在结尾添加另一个键/选项时就不会混淆。在这种情况下,我建议使用:

alias history='history -i'

当然,您可以将结果直接通过管道传递,例如:

% history | grep alias

4   2019-10-07 18:13:59  cat verybigaliasfile.txt
5   2019-10-07 18:13:59  alias 
9   2019-10-07 18:13:59  alias 

在这种情况下,duration不会出现,但其余部分相同。

当您想要grep histfile时,这是如何工作的? - posdef
1
我重写了整个答案,现在我解释了简单的别名加grep,还有一个自定义过滤器uhistory.awk - DrBeco
谢谢,你的脚本真的很有帮助。 - jlainoc
我很高兴它能为你提供帮助。 - DrBeco

2

2
补充:您可以使用history命令本身来翻译保存的历史文件中发现的时间戳:
如Nicholas Riley所解释的history命令选项同样适用于保存的历史文件,因此history -d < historyfile(或任何其他选项)可以很好地翻译时间戳。
如果您使用超过一个历史文件,则这非常方便-我已经设置了zsh以每个pty保留一个历史文件,以避免混淆在同一系统上并行运行的shell的历史记录(因为通常每个窗口/屏幕/ ... 都是特定于某个任务的,因此从正常使用中出现的历史记录最终会被分类主题)。

1
history -d < historyfile 对我不起作用。它只打印当前历史记录,而不是文件中给出的历史记录。 - olejorgenb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接