将历史文件中的哈希标签时间戳转换为所需字符串。

9
当我通过SSH将“history”命令的输出存储到文件中时,我会得到类似以下内容的结果:
ssh -i private_key user@ip 'export HISTFILE=~/.bash_history; export HISTTIMEFORMAT="%D-%T "; set -o history; history' > myfile.txt

输出

#1337431451
command

据我所学,这个哈希字符串代表一个时间戳。如何将它转换成我想要的字符串格式?

P.S.- 在SSH中使用历史记录时不会输出时间戳。已经尝试过几乎所有方法。因此,下一个最好的做法是自己将这些#时间戳转换为可读的日期时间格式。我该怎么做?


2
你确定目标主机上的'user'用户默认使用的是'bash'作为shell吗?我问这个问题是因为'HISTTIMEFORMAT'是用于格式化bash中时间戳的。所以你的命令应该已经满足你的需求了。 - Rajesh J Advani
2
date -d @1337431451 '+%D-%T' 输出 "05/19/12-07:44:11"。 - Dennis Williamson
@RajeshJAdvani 是的,Bash shell 存在。我也执行了 echo $SHELL。 - user1356163
是的,@RajeshJAdvani,它确实输出了历史记录。但问题是,它给出的时间戳不正确,而是给出当前时间(即如果我在3点执行命令,则历史记录中的所有命令都将显示为在3点执行)。 - user1356163
历史记录(至少到Bash 4.3.30)如果无法识别时间戳,则显示登录时间。我发现这是多行命令的情况。如果多行命令的某些行看起来像时间戳,它也会解释这些行。 - xebeche
你有GNU的date吗?或者,你的bash有多新?非常新的版本已经将内置的strftime支持折叠到printf中了。 - Charles Duffy
3个回答

7
您可以使用“粘贴”命令组合行:
paste -sd '#\n' .bash_history

使用awk中的strftime转换日期:

echo 1461136015 | awk '{print strftime("%d/%m/%y %T",$1)}'

作为结果,带有时间戳的Bash历史记录可以被下一个命令解析:
paste -sd '#\n' .bash_history | awk -F"#" '{d=$2 ; $2="";print NR" "strftime("%d/%m/%y %T",d)" "$0}'

将其转换为:

#1461137765
echo lala
#1461137767
echo bebe

to

1 20/04/16 10:36:05   echo lala
2 20/04/16 10:36:07   echo bebe

您可以创建脚本,例如/usr/local/bin/fhistory,其内容如下:
#!/bin/bash

paste -sd '#\n' $1 | awk -F"#" '{d=$2 ; $2="";print NR" "strftime("%d/%m/%y %T",d)" "$0}'

下面的命令可以快速解析bash历史文件:

fhistory .bash_history

4

有趣的问题:我尝试过,但是没有找到在非交互式 shell 中访问历史记录的简单和清晰的解决方案。然而,历史记录文件的格式很简单,您可以编写一个脚本来解析它。下面的 Python 脚本可能会很有用。使用 ssh -i private_key user@ip 'path/to/script.py .bash_history' 调用它:

#! /usr/bin/env python3

import re
import sys
import time

if __name__ == '__main__':
    pattern = re.compile(br'^#(\d+)$')
    out = sys.stdout.buffer
    for pathname in sys.argv[1:]:
        with open(pathname, 'rb') as f:
            for line in f:
                timestamp = 0
                while line.startswith(b'#'):
                    match = pattern.match(line)
                    if match: timestamp, = map(int, match.groups())
                    line = next(f)
                out.write(time.strftime('%F %T ', time.localtime(timestamp)).encode('ascii'))
                out.write(line)

我好像没有Python。我正在使用的电脑大约6-7年左右,我想。 - user1356163

2

仅使用Awk并以稍微准确的方式:

awk -F\# '/^#1[0-9]{9}$/ { if(cmd) printf "%5d  %s  %s\n",n,ts,cmd;
  ts=strftime("%F %T",$2); cmd=""; n++ }
  !/^#1[0-9]{9}$/ { if(cmd)cmd=cmd " " $0; else cmd=$0 }' .bash_history

这个程序只解析以时间戳格式开头的行(/^#1[0-9]{9}$/),编译直到下一个时间戳之前的所有后续行,使用空格(1个空格)组合多行命令,并以类似于history的格式打印命令,包括编号。请注意,如果有多行命令,则编号可能不匹配。 如果没有编号,并且使用换行符分隔多行命令:
awk -F\# '/^#1[0-9]{9}$/ { if(cmd) printf "%s  %s\n",ts,cmd;
  ts=strftime("%F %T",$2); cmd="" }
  !/^#1[0-9]{9}$/ { if(cmd)cmd=cmd "\n" $0; else cmd=$0 }' .bash_history

最后,使用GNU Awk(gawk)的快速且简单的解决方案也可以对列表进行排序:
gawk -F\# -v histtimeformat="$HISTTIMEFORMAT" '
    /^#1[0-9]{9}$/ { i=$2 FS NR; cmd[i]="" }
    !/^#1[0-9]{9}$/ { if(cmd[i]) cmd[i]=cmd[i] "\n" $0; else cmd[i]=$0 }
    END { PROCINFO["sorted_in"] = "@ind_str_asc"
       for (i in cmd) { split(i,arr)
       print strftime(histtimeformat,arr[1]) cmd[i]
    }
}'

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