【问题标题】:Bash: how to duplicate input/output from interactive scripts only in complete lines?Bash:如何仅在完整的行中复制交互式脚本的输入/输出?
【发布时间】:2014-06-28 02:00:49
【问题描述】:

如何实时捕获脚本的输入/输出(例如使用 tee),但逐行而不是逐个字符?我的目标是仅在退格和自动完成完成处理后(按 RETURN 键后)捕获键入到脚本的交互式提示中的输入。

具体来说,我正在尝试为 ssh 创建一个包装脚本,该脚本创建一个带有时间戳的远程服务器上使用的命令日志。 The script 使用 tee 重定向输出以进行过滤,效果很好,但是每当我使用退格键或向上/向下键滚动浏览远程历史记录时,重定向的输出就会与未提交的字符混杂在一起。例如:service test stopexitservice test stopartcd ..logs[1Pls -al

也许有一种方法可以捕获终端的回滚并像使用 tee 一样重定向?

更新:我找到了一个character-based cleanup solution,它大部分时间都能满足我的需求。但是,我仍然希望得到这个问题的答案(这很可能是 msw 很难做到的答案)。

【问题讨论】:

  • 试试这个来自 unix.stackexchange.com 的答案:unix.stackexchange.com/questions/14684/…。但是,最好在远程机器上使用 bash 历史记录。
  • 因为我经常连接到这么多不同的远程服务器,所以我需要一种将日志保存在本地的自动化方式。链接中的一个答案处理退格擦除,但不是向上/向下命令完成,这会导致在通过命令 exitservice test stopservice test start 分页时生成诸如 service test stopexitservice test stopart 之类的日志(即使我实际上不要使用这些命令)。不过,谢谢!
  • 为每个登录会话创建一个新的历史文件(带有时间戳)。确保其经常更新。编写一个小型 crontask,将历史文件(使用 sftp)移动到本地存储库。 rsync 可能会有所帮助。如有必要,编写一个 ssh 包装器来记录您连接到的远程计算机(但您必须避免从远程计算机进行 ssh。)另一种选择:使用 sshfs 将历史文件保存在本地计算机上。
  • 这可能是我唯一的选择,但我仍然希望有一个本地解决方案。远程服务器大多不是由我管理的,登录通常是 root 或共享的(当然是非生产的),并且 ssh 会话通常是链式的,因此调整所有服务器的历史记录甚至运行自动下载会很耗时,而且/ 或不礼貌。
  • 然后在您的提示中添加一个时间戳。 (PS1)——或者弄清楚如何使用 bash 历史来实现它,我仍然认为这是你最好的选择。

标签: bash ssh io-redirection tee


【解决方案1】:

在 Unix 世界中,有两种处理键盘输入的主要模式。这些被称为“原始”,其中字符一次从终端传递到阅读程序。这是编辑器(等)将使用的模式,因为编辑器需要在您按下键时立即响应。

另一个终端规则称为“cooked”,它是您认为是 bash 逐行输入的逐行行为,您可以在其中退格,并且在您按回车之前不会执行命令。 SSH 必须以原始的、逐个字符的模式接收您的输入,因为它不知道另一端正在运行什么。例如,如果您在远端运行编辑器,它不能等待返回,然后发送按键。因此,正如一些人所建议的那样,获取远端的 shell 历史记录是获取您键入的 bash 命令的逐个命令记录的唯一合理方法。


为了清楚起见,我过度简化了;实际上大多数 bash 安装都以原始模式输入,因为它们允许像命令修改一样的编辑器。例如,Ctrl-P 向上滚动命令历史记录或 Ctrl-A 转到行首。并且 bash 需要能够在输入时获取这些键,而不是等待返回。

这是在本地端捕获非常困难的另一个原因:如果在本地端捕获,流将充满退格键和所有 bash 的编辑命令。要获得远程 shell 实际执行内容的真实记录,您必须像解析远程 shell 一样解析字符流。如果你运行类似的东西也会有问题

vi /some_file/which_is_on_the_remote/machine

本地 ssh 的输入流将充满移动命令 sn-ps 文本,包括退格等.

很少有涉及计算机的事情是不可能的;从 ssh 调用的本地端获取干净的输入非常非常困难。

【讨论】:

  • 感谢您的精彩解释。我现在在想,我最大的希望是以某种方式捕获终端回滚。也一样难吗?
  • 回滚解析最好作为一个单独的问题提出吗?
  • 接受 - 我猜“没有办法”是答案:)。
【解决方案2】:

我质疑记录您在本地或远程机器上执行的命令的实际用途。原因是命令日志中看不到太多状态。作为一个简单的例子,这里有两个命令的日志:

17:00$ cp important_file important_file.bak
17:15$ rm important_file

两天后,您试图确定important_file.bak 是否应该包含您想要的内容。鉴于该日志,您无法回答那个简单的问题。即使你有序列

16:58$ cat important_file
17:00$ cp important_file important_file.bak
17:15$ rm important_file

如果您没有捕获输出,则日志中的cat 不会告诉您任何信息。给我几乎任何命令序列,我可以设想这样一个场景,它不会为您提供理解所做操作所需的信息。

【讨论】:

  • 立即,脚本的目的是大致记录我如何度过我的时间。 1) 我有一个用于计费的自动时间跟踪系统,并且 ssh 会话目前无法记录日志。 2) 最好告诉我的客户我对他们的服务器做了什么(以防万一),即使他们没有设置正确的日志记录。至少,我认为原则上这是一种很好的做法。不过,您对输出有一个很好的看法。该脚本仅限于某些用途。
【解决方案3】:

出于非常相似的目的,我使用 GNU screen,它提供了记录您在 shell 会话(输入/输出)中所做的一切的选项。它创建的日志也带有不受欢迎的字符,但我用 perl 清理它们:

perl -ne 's/\x1b[[()=][;?0-9]*[0-9A-Za-z]?//g;s/\r//g;s/\007//g;print' < screenlog.0

我希望这会有所帮助。

screen的一些特点: http://speaking-my-language.blogspot.com/2010/09/top-5-underused-gnu-screen-features.html

我找到了 perl-oneliner 的网站: https://superuser.com/questions/99128/removing-the-escape-characters-from-gnu-screens-screenlog-n

【讨论】:

  • 感谢您的提示,但屏幕上/下完成似乎有同样的问题。我用 C-a H 记录了一个会话,在我的命令历史记录中上下翻页,得到了输出:test[2Plsasastest[K。这些命令都没有在我的会话中实际使用,只是分页。
  • 我也注意到屏幕有一个回滚转储功能,但是如何利用它来实时逐行输出呢?也许每秒回滚之间的差异?
  • 我认为您不能逐行插入时间戳,但您可以每分钟转储一个时间戳:aperiodic.net/screen/commands:logtstamp
猜你喜欢
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
  • 2016-09-19
  • 2021-09-19
  • 2011-09-13
  • 1970-01-01
  • 2014-02-28
  • 1970-01-01
相关资源
最近更新 更多