如何查看已完成终端命令的所有先前输出?

Jon*_*ron 7 linux terminal bash command-line

我在 gnome 终端中执行了一个命令,该命令向终端打印的输出比我预期的要多。我想阅读整个输出,但终端滚动在到达开始之前停止。

我知道我可以更改终端配置文件设置以启用无限滚动,或将输出通过管道传输到文件等。但是,所有这些常见解决方案都适用于未来的输出。

如何查看已执行命令的完整终端输出?

编辑:好吧,这是不可能的。谢谢大家!

Arg*_*uts 8

我的经验是,评论中的共识是正确的 - 一旦超出终端的缓冲区,数据就会丢失(或者就像 - 它可能在尚未被覆盖的内存中) - 因此你无法追溯增加缓冲区大小。

这个答案介于评论、答案之间,也许对你的情况来说有点矫枉过正。这更像是一种可能解决您的情况的建议方法 - 特别是直到为时已晚才知道您需要日志的问题(非因果问题很难),但它并不是对您问题的直接答案。

无论如何,评论太长了。我没有明确列出实现此方法所需的所有代码,主要是因为需要做出一堆实现决策;如果您需要更详细的信息,我很乐意提供。

Script相处起来一点也不愉快

首先,该script实用程序被建议作为“权宜之计”,以防止数据丢失而不增加缓冲区大小(设置为无限制时会产生安全隐患)。如果说有哪个公用事业公司需要一些细心呵护的话,script那就是它了。话又说回来,它是内核团队开发的。你可以随意阅读。

我发现script经常比它的价值更麻烦(对其进行后处理以使其半人类可读等),并且开始使用简化的方法来记录 stdout、stdin 和/或 stderr。从某种意义上说,这是重新创建脚本,但具有完全控制权,而不是受硬编码日志script记录设置的支配。

这种方法可以相对无缝地集成到您的 shell 会话中,并且在极少数情况下,您确实溢出了终端缓冲区,您将拥有一个包含这些内容的临时文件。为了保持日志记录“干净”,您必须执行一些内务处理步骤。此外,默认情况下也会存在相同的安全问题(所有终端输出的日志);然而,有一种简单的方法可以加密日志。

有 3 个基本步骤:

  1. 配置重定向,以便将 stdout(和 stderr,如果需要)拆分到文件和终端。我使这个示例保持简单,并且没有将 stdin 或 stderr 定向到文件 - 但是如果您理解 stdout 重定向示例,那么其余的事情就很简单了。
  2. 配置 .bashrc,以便每当打开 shell 时都会启动此日志记录。
  3. 当给定的 shell 关闭时,使用内置的 bashTRAP调用用户代码,这将终止会话日志记录(您可以删除文件、归档文件等)

通过这种方法,您将有效地拥有一个隐形的安全网,该安全网将允许查看给定 shell 会话的整个历史记录(基于您重定向的内容 - 再次,为了简化事情,我只显示标准输出);当你不需要它时,你甚至不应该知道它的存在。

细节

1. 配置重定向

以下代码片段将创建一个文件描述符 3,它指向一个日志文件。stdout 被重定向到 3,然后使用tee,我们将该流拆分回终端(相当于 stdout)。您可以轻松地将 stderr 添加到同一命令/日志文件,将其通过管道传输到不同的文件,或保留原样(未记录)。

logFile=$(mktemp -u)
exec 3>&1 1> >(tee $logFile >&3)
Run Code Online (Sandbox Code Playgroud)
  • 您会发现这个日志文件比脚本生成的日志文件要干净得多;它不存储退格键、换行符和其他经常不需要的特殊字符。

  • 请注意,如果您希望对日志文件进行加密,您可以通过openssl在 tee 命令之后添加一个额外的管道阶段来相当轻松地做到这一点。

2.自动化日志生成

在.bashrc中添加与上面相同的代码。每次创建新 shell 时,都会创建特定于该会话的日志文件。

export logFile=$(mktemp -u)
exec 3>&1 1> >(tee $logFile >&3)
echo "Current session is being logged in $logFile"
Run Code Online (Sandbox Code Playgroud)

3. shell关闭时自动关闭日志记录

如果您希望在会话结束时删除日志文件,您可以使用 bash 内置trap函数来检测会话是否结束,并调用一个函数来处理日志文件,例如(也在 .bashrc 中)。

trap closeLog EXIT

closeLog () {
  rm -f "$logFile" >/dev/null 2>&1
}
Run Code Online (Sandbox Code Playgroud)

会话日志记录清理可以通过多种不同的方式进行处理。当 shell 通过捕获“退出”信号关闭时,将调用此方法。此时,您可以删除日志文件、移动它/重命名它,或者进行任意数量的清理操作。您还可以通过 cron 作业而不是通过 TRAP 来清理日志文件(如果使用这种方法,如果您还没有为 /tmp 目录配置一个清理任务,我建议您执行定期清理任务;就好像bash shell 崩溃 EXIT 陷阱不会被触发)。

处理子 shell 的注意事项

子 shell 会出现一个有趣的情况。如果在现有的交互式 shell 之上打开一个新的交互式 shell,则会创建一个新日志,并且一切都应该正常工作。当退出该 shell(返回到父级)时,将恢复登录该文件。如果您想更干净地解决这个问题 - 也许甚至维护子 shell 的公共日志(交互式或其他方式),您将需要检测(在 .bashrc 中)您是否位于嵌套子 shell 中,并重定向到父级的日志文件而不是创建一个新的。您还需要检查您是否位于子 shell 中,以便您的“陷阱”调用不会在退出时删除父级的日志文件。您可以从 bash 环境变量 SLVL 获取嵌套 shell 级别,该变量存储 shell 堆栈的“深度”。

请注意保持日志“干净”:

如果您确实将标准输入重定向到日志文件,您最终会得到许多与脚本实用程序生成的相同的不需要的工件。这可以通过在重定向和文件之间添加过滤器阶段(例如 sed/grep)来解决。只需创建一个正则表达式来删除您不想记录的任何内容。要完全清理它需要一些相当深入的处理(可能在写入文件之前缓冲每个新行,清理然后写入)。否则,将很难知道退格键何时是“垃圾”或有意的。