converting the hash tag timestamps in history file to desired string
Asked Answered
F

3

9

when i store the output of history command via ssh in a file i get something like this

ssh -i private_key user@ip 'export HISTFILE=~/.bash_history; export HISTTIMEFORMAT="%D-%T "; set -o history; history' > myfile.txt

OUTPUT

#1337431451
command

as far as ive learnt this hash string represents a timestamp. how do i change this to a string of my desired format

P.S- using history in ssh is not outputting with timestamps. Tried almost everything. So i guess the next best thing to do would be to convert these # timestamps to a readable date time format myself. How do i go about it?

Florina answered 19/5, 2012 at 12:58 Comment(6)
Are you sure that 'user' on the destination has 'bash' as the default shell? The reason I ask is, HISTTIMEFORMAT is used to format the timestamp in bash. So your command should already do what you need.Ethiop
date -d @1337431451 '+%D-%T' outputs "05/19/12-07:44:11"Warmonger
@RajeshJAdvani Yea.. bash shell is present. i did an echo $SHELL alsoFlorina
yeah and it does output a history @RajeshJAdvani. But the problem is instead of giving the correct time stamp, it gives the present time (i.e if i execute the command at 3 o clock all commands in the history output will be shown as having been executed at 3 o clock)Florina
history (at least up to Bash 4.3.30) shows the time of login if it fails to recognize the timestamp. I found this since this is the case for multi-line commands. It also interprets lines of multi-line commands if they look like timestamps.Melanochroi
Do you have GNU date? Alternately, how new is your bash? Very new versions have built-in strftime support folded into printf.Sidwell
L
4

Interesting question: I have tried it but found no simple and clean solution to access the history in a non-interactive shell. However, the format of the history file is simple, and you can write a script to parse it. The following python script might be interesting. Invoke it with 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)
Low answered 19/5, 2012 at 13:55 Comment(1)
i dont have python, i think. The comp i'm working on is around 6-7 yrs old, i think.Florina
M
7

you can combine rows with paste command:

paste -sd '#\n' .bash_history

and convert date with strftime in awk:

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

as a result bash history with timestamp can be parsed by the next command:

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

which converts:

#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

also you can create script like /usr/local/bin/fhistory with content:

#!/bin/bash

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

and quickly parse bash history file with next command:

fhistory .bash_history
Melancholy answered 20/4, 2016 at 7:38 Comment(0)
L
4

Interesting question: I have tried it but found no simple and clean solution to access the history in a non-interactive shell. However, the format of the history file is simple, and you can write a script to parse it. The following python script might be interesting. Invoke it with 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)
Low answered 19/5, 2012 at 13:55 Comment(1)
i dont have python, i think. The comp i'm working on is around 6-7 yrs old, i think.Florina
M
4

Using just Awk and in a slightly more accurate way:

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

This parses only lines starting with something that looks like a timestamp (/^#1[0-9]{9}$/), compiles all subsequent lines up until the next timestamp, combines multi-line commands with " " (1 space) and prints the commands in a format similar to history including a numbering.

Note that the numbering does not (necessarily) match if there are multi-line commands.

Without the numbering and breaking up multi-line commands with a newline:

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

Finally, a quick and dirty solution using GNU Awk (gawk) to also sort the list:

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]
    }
}'
Melanochroi answered 17/9, 2016 at 11:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.