如何从其他tty上运行的shell进程中获取bash历史logging或最后x个数字行

有趣的一点困境。 这是Centos。 昨晚我login到一个tty物理控制台。 我发起了一个命令,让它通宵运行。 该tty仍然login,但我目前通过SSH远程login(我不在控制台。)

我想知道我使用的确切命令参数(我不记得),所以我想看看我在那个tty上运行的命令。 由于shell仍在运行,它没有写任何东西给bash_history – 那个实例的历史logging仍然在内存中。

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

(a)向正在运行的shell发送一个信号,让它转储它的bash历史(b)检查运行shell的环境以获得它的历史信息(c)从tty会话中检查最近的x行,我可以看到我input的内容

或一些其他手段….

好的,我明白了。 这实际上是一个非常漂亮的事情要知道,因为我可以预见它有很多用途。

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

  2. 确定有问题的bash进程的pid(你想redirectinput和输出)。 这个进程当前与一个terminal设备如/ dev / tty1相关联

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

    一个。 p dup2(open(“/ dev / pts / 2”,0),0)#这会改变目标进程的标准input

    湾 p dup2(open(“/ dev / pts / 3”,1),1)#这会改变目标进程的标准输出

    C。 p dup2(open(“/ dev / pts / 3”,1,),2)#这会改变目标进程的标准err

    d。 分离

    即 放弃

换句话说,步骤3所做的是使窗口2成为标准input,而窗口3成为输出。

4.从窗口1(/ dev / pts / 1),“ls -l / proc / [pid] / fd”来validation我们想要操作的bash进程的文件描述符更改

5.你在窗口2中键入的内容现在被送到两个地方:与这个窗口相关联的原始bash shell和目标进程。 因此,从窗口2(/ dev / pts / 2)键入“hhiissttoorryy [return] [return]”。 你必须input两次的原因是因为input被分解到当前的bash shell和目标bash shell。 这是因为操作知道/ dev / pts / 2的键盘input有两个来源,它可以公平地分配你input的字符。 第一个字符到一个目的地,下一个到第二个目的地,等等。如果你有三个进程的标准input是/ dev / pts / 3,那么你必须input每个字符三次。 内核以循环方式将input字符馈送给收件人。

6.你可以通过临时设置原始Window 2 bash shell的stdin到一些未使用的设备,如/ dev / tty5或其他东西来解决上述不便。 这使得/ dev / pts / 2键盘成为只有一个进程的标准input(而不是两个)。 现在你可以正常input命令了(它们只是不会回显到你所在的屏幕上,而是会被回显到/ dev / pts / 3)。

7.因为你键入了“历史”,它被送到目标进程,它的stdout是3号窗口,切换到3号窗口,你可以看到命令输出。 现在你有目标bash shell的命令历史了。

8.回到窗口1,在[pid]上再次使用gdb将目标shell的标准错误重置为原始值(/ dev / tty1)。 你也可以将Window 2 stdin设置回它应该是的。

  1. 如果你喜欢,你可以清除额外的文件描述符,通过删除它们与'exec 3>& – '删除fd 3例如

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

我没有尝试过,但是你可以通过打开一个shell,确定它的tty或pty,临时设置shell的分配标准到一个不需要的设备,分配tty / pty作为目标shell的标准input/输出。 通过这种方式,您可以在目标shell中使用单个屏幕进行所有input和输出。

总结:通过上面的过程,只要你有一个你可以访问的shell,你可以用它作为系统上任何其他进程/ shell的标准input/输出。 例如,如果您希望与在控制台上运行的shell进行交互,但是您没有对主机的物理访问权(或熄灯的解决scheme),则这很有用。 这当然可以推广到任何情况下,你想要一个特定的shell来控制你所select的任何进程的input/输出。

我仍然半决定地面对这种情况,最后想出了一些简单的方法从我的“孤立的”bash会话中恢复内存中的历史命令:

(注意:在下面的每个例子中,将PIDreplace为孤立的bash会话的进程ID)

有效地触发history -a

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

将最近10个历史logging转储到本地terminal(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上testing了bash 4.3。
  • 在我的系统上,我不得不使用sudo gdb调用 – 甚至可以访问我自己的bash进程。
  • 如果调用成功,那么你应该看到$1 = 0 (如果你看到其他值,它们很可能是errno的 – 就像试图附加到一个还不存在的文件时,你会得到$1 = 2 (ENOENT) )。
  • 这种方法是基于研究bash C代码响应history命令做什么的; 例如: builtins / history.def#L203-L212

您可以从/proc/${PID}/cmdline获取此信息。