有效触发history -a:

有效触发history -a:

有趣的小困境。这是 Centos。昨晚我在 tty 上登录了物理控制台。我启动了一个命令并让它运行了一整夜。tty 仍然登录,但我目前通过 ssh 远程登录(我不在控制台旁)。

我想知道我使用的确切命令参数(我不记得了),所以我想看看我在该 tty 上运行的命令。由于 shell 仍在运行,因此它尚未将任何内容写入 bash_history - 该实例的历史记录仍在内存中。

所以,我的问题是是否有办法远程检索我想要的东西,也许:

(a)向正在运行的 shell 发送信号,使其转储其 bash 历史记录(b)检查正在运行的 shell 的环境以获取其历史记录信息(c)检查 tty 会话中最近的 x # 行,以便我可以看到我输入的内容

或者其他方法....

答案1

好的,我明白了。这实际上是一件很棒的事情,因为我可以预见它有很多用途。

  1. 打开到远程主机的 ssh 会话。启动带有几个窗口的 screen 或 tmux 会话。您可以通过键入“tty”来确定每个窗口的伪设备。假设我们有“/dev/pts/[123]”对应于我们在 screen 会话中运行的三个 shell

  2. 确定相关 bash 进程的 pid(您要为其重定向输入和输出的进程)。此进程当前与终端设备(如 /dev/tty1)相关联

  3. 从屏幕窗口 1 运行“gdb -p [pid]”并在 gdb 中运行以下命令:

    a.p dup2(open("/dev/pts/2",0),0) # 这将改变目标进程的标准输入

    b. p dup2(open("/dev/pts/3",1),1) # 这将改变目标进程的标准输出

    c.p dup2(open("/dev/pts/3",1,),2) # 这会改变目标进程的标准错误

    d. 分离

    e. 退出

换句话说,步骤 3 所做的就是将窗口 2 作为标准输入,将窗口 3 作为输出。

4.从窗口 1 (/dev/pts/1),使用“ls -l /proc/[pid]/fd”来验证我们要操作的 bash 进程的文件描述符是否发生变化

5.您在窗口 2 中输入的内容现在被传送到两个地方:与此窗口关联的原始 bash shell 和目标进程。因此,从窗口 2 (/dev/pts/2) 中输入“hhiissttoorryy[return][return]”。您必须将所有内容输入两次的原因是因为输入被分为当前 bash shell 和目标 bash shell。这是因为操作系统知道有两个源正在利用 /dev/pts/2 的键盘输入,并且它会公平地分配您输入的字符。第一个字符进入一个目的地,下一个进入第二个目的地,等等。如果您有三个进程,其 stdin 是 /dev/pts/3,那么您必须输入每个字符三次。内核以循环方式将输入字符提供给接收者。

6.您可以通过将原始 Window 2 bash shell 的 stdin 临时设置为某个未使用的设备(如 /dev/tty5 等)来解决上述不便。这会使 /dev/pts/2 键盘成为仅一个进程(而不是两个)的标准输入。现在您可以正常输入命令(它们不会回显到您所在的屏幕,而是会回显到 /dev/pts/3。)

7.由于您输入了“history”,并且它被输入到目标进程,其标准输出是窗口 3,请切换到窗口 3 以便您可以看到命令输出。现在您有了目标 bash shell 的命令历史记录。

8.返回窗口 1,再次对 [pid] 使用 gdb,将目标 shell 的标准输入、输出、错误重置为原始值 (/dev/tty1)。您还可以将窗口 2 的 stdin 重置为应有的值。

  1. 如果你愿意,你可以通过使用“exec 3>&-”删除多余的文件描述符来清理它们,例如删除 fd 3

请注意,当您在正在运行的进程上运行 gdb 时,它会以与 SIGSTOP 相同的方式暂停进程的执行。当您“分离”它时,它会像在 SIGCONT 中一样恢复。这允许您操作文件描述符而不会产生不利后果。

我没有尝试过,但您可能可以通过打开 shell、确定其 tty 或 pty、临时将 shell 的指定标准输入和输出设置为未使用的设备、将 tty/pty 指定为目标 shell 的标准输入/输出,使上述操作更加简单和用户友好。这样,您就可以使用单个屏幕进行目标 shell 的所有输入和输出。

总结:通过上述过程,只要您拥有可以访问的 shell,就可以将其用作系统上任何其他进程/shell 的标准输入/输出。例如,如果您想要与控制台上运行的 shell 进行交互,但又无法物理访问主机(或无人值守解决方案),那么这种方法就非常有用。当然,这可以推广到您希望特定 shell 控制您选择的任何进程的输入/输出的任意情况。

答案2

我仍然会时不时地遇到这种情况,最后我想出了一些更简单的方法来从我的“孤立的” bash 会话中恢复内存中的历史命令:

(注意:在下面的每个示例中,将其替换PID为孤立的 bash 会话的进程 ID)

有效触发history -a

$ gdb -p PID -batch -ex 'call maybe_append_history(get_string_value("HISTFILE"))'

将最后 10 条历史记录转储到本地终端 (pty)

$ gdb -p PID -batch -ex 'call append_history(10, "'$(tty)'")'

将整个历史记录备份到临时文件:

$ gdb -p PID -batch -ex 'call write_history("/tmp/history-backup.txt")'

笔记:

  • 在 Ubuntu 16.04.01 上使用 bash 4.3 进行测试。
  • 在我的系统上,我必须调用sudo gdb-- 甚至才能访问我自己的 bash 进程。
  • 如果调用成功,那么您应该看到$1 = 0(如果您看到其他值,它们很可能errno是 - 就像当试图附加到尚不存在的文件时,您将得到$1 = 2(ENOENT))。
  • 这种方法基于研究 bash C 代码对history命令的响应;例如:内置/history.def#L203-L212

答案3

您也许可以从 获得此信息/proc/${PID}/cmdline

相关内容