如何将带有时间戳的命令历史连续输出到终端?


9

我使用一个简单的别名来启用一个或多个终端窗口中的命令“跟踪”:

alias trackmi='export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"'

然后,我将tail -f我的.bash_history文件放在工作区的另一个终端中,以立即获得反馈。我刚刚启用了无限的历史记录,export HISTTIMEFORMAT="[%F %T] ".bashrc中更新了我的历史记录格式()。当然,该history命令会显示时间戳。但是历史文件本身的格式为:

#1401234303
alias
#1401234486
cat ../.bashrc 

我该如何转换Unix时间并像显示命令一样将整个命令显示在一行上history,包括编号:

578  [2014-05-27 19:45:03] alias
579  [2014-05-27 19:48:06] cat ../.bashrc 

...然后遵循。还是找到一种将history命令输出连续输出到终端的方法?

Answers:


7

使用GNU awk

tail -fn+1 ~/.bash_history | awk '
  /^#/{printf "%-4d [%s] ", ++n, strftime("%F %T", substr($0, 2)); next}; 1'

如果我更新其他解决方案以fn+1进行比较,那么效果很好,最初显示速度更快!谢谢!

5

这是在分屏xterm上运行的最终产品,从基本的外壳默认值到仅使用几个命令即可工作:

在此处输入图片说明

比屏幕截图中展示的方法更粗糙的方法看起来像这样:

PS1='$( { date ; fc -l -0 ; } >${TGT_PTY} )'$PS1

${TGT_PTY}tty实际在想要输出的屏幕上运行交互式shell时,从命令中得到的结果将是什么。或者,实际上,您可以使用任何可写文件,因为它本质上仅是文件重定向的目标。

我将pty语法用于伪终端,因为我假设它是某种xterm,但您可能也很容易将vt专用化-并且流式传输的历史记录始终只是CTRL-ALT-Fn键组合。如果是我,我可以将这两个概念结合起来,并在专用的vt上作为一个会话screentmux会话。但是我离题了。

在刚启动的计算机上,我在/bin/login典型的Linux getty控制台上看到了典型的提示。我按一下CTRL-ALT-F2即可访问一个不太典型的kmscon控制台,该控制台的行为更像是xterma而不是a tty。我输入命令tty并收到响应/dev/pts/0

通常,xterms使用伪终端将单个终端设备多路复用为多个终端 -因此,如果您要通过在终端选项卡或窗口之间切换来在X11中执行类似的操作,您可能也会收到类似的输出/dev/pts/[0-9]*。但是使用CTRL-ALT-Fn组合键访问的虚拟终端控制台是真正的终端设备,因此会获得自己的/dev/tty[0-9]*名称。

这就是为什么登录控制台2后,当我tty在提示符下键入时的响应是,/dev/pts/0但是当我在控制台1上执行相同的操作时,输出是/dev/tty1。无论如何,回到控制台2然后执行:

bash
PS1='$( { date ; fc -l -0 ; } >/dev/tty1 )'$PS1

没有明显的效果。我继续输入一些命令,然后CTRL-ALT-F1再次按切换到控制台1 。在这里,我发现重复的条目看起来像<date_time>\n<hist#>\t<hist_cmd_string>在控制台2上键入的每个命令一样。

但是,除非直接写入终端设备,否则另一个选项可能类似于:

TGT_PTY=
mkfifo ${TGT_PTY:=/tmp/shell.history.pipe}
{   echo 'OPENED ON:'
    date
} >${TGT_PTY}

然后也许...

less +F ${TGT_PTY}

粗略的提示命令不符合您的要求-都没有格式字符串,date也没有格式选项fc-但它的机制并不需要太多:每次您的提示呈现上一个历史记录命令时,当前日期和时间都被写到${TGT_PTY}您指定的文件。就这么简单。

观看和打印shell历史记录是fc的主要目的。它是内置的外壳,即使date不是。中zsh fc可以提供各种精美的格式设置选项,其中一些适用于时间戳。当然,如你上面的注意,bashhistory可以做同样的。

为了获得更清晰的输出,您可以使用我在这里更好地解释过的技术在当前shell中设置持久跟踪变量,尽管必须在提示序列中对其进行跟踪并在子shell中对其进行处理。

这是格式化为您的规格的便携式方法:

_HIST() { [ -z ${_LH#$1} ] ||
    { date "+${1}%t[%F %T]"
      fc -nl -0 
    } >${TGT_PTY}
    printf "(_LH=$1)-$1"
}

: "${_LH=0}"
PS1='${_LH##*[$(($(_HIST \!)))-9]}'$PS1

我实现了last_history计数器$_LH,该计数器仅跟踪最新更新,因此您不会两次写出相同的历史记录命令-例如,仅用于按Enter键。要使变量在当前外壳中递增,需要进行一些争吵,以便即使在子外壳中调用该函数也可以保留其值-再次在链接中对此进行了详细说明。

它的输出看起来像 <hist#>\t[%F %T]\t<hist_cmd>\n

但这只是完全可移植的版本。使用bash它可以用更少的精力并且仅通过实现shell内置函数来完成-当您认为这是每次按下时都会运行的命令时,这可能是合乎需要的[ENTER]。有两种方法:

_HIST() { [ -z ${_LH#$1} ] || {
        printf "${1}\t[%(%F %T)T]"
        fc -nl -0
    } >${TGT_PTY}
    printf "(_LH=$1)-$1"
}
PROMPT_COMMAND=': ${_LH=0};'$PROMPT_COMMAND
PS1='${_LH##*[$(($(_HIST \!)))-9]}'$PS1

另外,您也可以使用bashhistory命令_HIST以这种方式定义函数:

_HIST() { [ -z ${_LH#$1} ] || 
        HISTTIMEFORMAT="[%F %T]<tab>" \
        history 1 >${TGT_PTY}
    printf "(_LH=$1)-$1"
}

这两种方法的输出都看起来像:<hist#>\t[%F %T]\t<hist_cmd>\n尽管该history方法包括一些前导空格。不过,我相信该history方法的时间戳会更加准确,因为我认为他们无需等待引用的命令完成就可以获取其戳记。

你可以不惜一切在两种情况下跟踪任何状态下,只要你以某种方式与过滤信息流uniq-因为你可能会做mkfifo,因为我前面提到的。

但是在这样的提示中进行操作意味着仅在需要时才通过更新提示的方式来始终对其进行更新。这很简单。

您可能还会执行与您正在执行的操作类似的操作,tail而是进行设置

HISTFILE=${TGT_PTY}

我实际上是在另一个标签中进行编辑。
mikeserv

好吧,我现在实际上要点击保存,@illuminÉ-但您会看到我离开的地方...
mikeserv

@illuminÉ-顺便说一句-我希望我对此是正确的-我假设您以书面形式输入了命令,是${TGT_PTY}吗?如果是这样,它将解释“歧义重定向”,因为那将是一个空变量。您需要一个文件。/dev/pts/[num]在所有的可能性-
mikeserv

确实有效!印刷屏幕帮助!我希望您的第一个也是唯一的代码块是您在打印屏幕中输入的内容,并清楚地选择要输出到的pt,然后将选项卡输入到函数中-无需其他操作。在我看来,使用变量来描述我必须手动输入才能快速尝试的内容不是一个好习惯,因为您必须深入研究文本才能弄清楚所有内容,从而使解决方案难以理解。也祝您和家人一切顺利。

@illuminÉ-没关系,cat我很偏执。它可以正常工作-甚至12小时后也可以。
mikeserv

4

随意播放格式,但这(我相信)可以满足您的要求...保存到PATH中的某个位置,使可执行文件并享有:

#!/bin/bash
count=$(  echo "scale=0 ; $(cat ~/.bash_history | wc -l ) / 2" | bc -l )
tail -f ~/.bash_history | awk -v c=$count '{if($1 ~/^#/){gsub(/#/, "", $1);printf "%s\t", c; "date \"+%F %T\" --date @" $1 | getline stamp; printf "[%s]\t",stamp;c++}else{print $0}}'

我敢肯定它可以被优化,但是您明白了。

简要说明:由于〜/ .bash_history无法跟踪计数,因此我们首先确定条目数。然后,用一点awk魔术来正确设置格式,并跟踪条目数。


如果有多行条目,则不起作用。也tail -f将开始读取10条线已经被包含在你的count。假定在非POSIX环境中未设置GNU日期(未设置POSIXLY_CORRECT)。每个时间戳运行一个shell和一个date命令。
斯特凡Chazelas

@StephaneChazelas对于多行条目,在我的设置中,它们似乎已在两种解决方案中注册。我的设置中可能有东西吗?

1
@illuminÉ,tink count计数的行中的一半.bash_history,然后以每行开头#,因此递增,因此报告的历史记录计数可能是错误的。使用count=$(grep -c '^#' ...)可能会更好,但无论如何,这些历史记录数字最终可能会不同步,特别是如果您同时运行2个以上的bash。
斯特凡Chazelas

@StephaneChazelas真诚的,我不能完全欣赏任何一种解决方案,我非常感谢您的解释!实际上,计数是不同的,因此在这里要高得多。。。我可以看到您围绕strftime构建了自己的解决方案,这基本上就是history命令所利用的。

1
感谢@StephaneChazelas的反馈,我将看看我是否可以解决这些问题:)
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.