我如何看到在某些bash实例中正在执行的确切命令行?


29

我有一个运行时间很长的bash实例(在screen会话中),该实例在一个循环内执行一组复杂的命令(每个循环执行管道,重定向等)。

长命令行是在终端内部编写的-不在任何脚本中。现在,我知道bash进程ID,并且我具有root用户访问权限-如何查看在其中执行的确切命令行bash

bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

在另一个Shell实例中,我想查看在PID 1234中执行的命令行:

bash$ echo $$
5678
bash$ su -
sh# cd /proc/1234
sh# # Do something here that will display the string  \
   'while true ; do someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done'

这可能吗?

编辑#1

为我得到的一些答案添加反例。

  1. 关于使用cmdlineunder /proc/PID:至少在我的情况下不起作用。这是一个简单的例子:

    $ echo $$
    8909
    
    $ while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

    在另一个外壳中:

    $ cat /proc/8909/cmdline
    bash
  2. 使用ps -p PID --noheaders -o cmd同样没有用:

    $ ps -p 8909 --no-headers -o cmd
    bash
  3. ps -eaf 也无济于事:

    $ ps -eaf | grep 8909
    ttsiod    8909  8905  0 10:09 pts/0    00:00:00 bash
    ttsiod   30697  8909  0 10:22 pts/0    00:00:00 sleep 30
    ttsiod   31292 13928  0 10:23 pts/12   00:00:00 grep --color=auto 8909

    也就是说,我正在寻找的ORIGINAL命令行没有输出-即while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

Answers:


40

我知道我正在努力,但是UNIX永远不会失败!

这是我的管理方式:

bash$ gdb --pid 8909
...
Loaded symbols for /lib/i386-linux-gnu/i686/cmov/libnss_files.so.2
0xb76e7424 in __kernel_vsyscall ()

然后在(gdb)提示符下运行命令,call write_history("/tmp/foo")该命令会将历史记录写入文件/tmp/foo

(gdb) call write_history("/tmp/foo")
$1 = 0

然后,我脱离了流程。

(gdb) detach
Detaching from program: /bin/bash, process 8909

然后退出gdb

(gdb) q

果然...

bash$ tail -1 /tmp/foo
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

为了便于将来重复使用,我编写了一个bash脚本,使过程自动化。


1
+1非常好侦探。请务必在2天内将此标记为例外A。
slm

@slm:谢谢!我会写一篇关于它的博客文章-很好玩,把它弄下来。
ttsiodras 2014年

1
随着readline的激活,您也可以做到这一点的gdbprint (char *)rl_line_buffer。序列中的当前命令为 print (char *)the_printed_command。您也可以call history_builtin(),但这将在bash进程的tty上输出,因此它可能没什么用处。
2014年

11
@slm:无法抗拒-我在这里写过
ttsiodras 2014年

1
bash是线程安全的吗?您将不得不希望自己不要修改某些内部状态,从而在执行gdb中的某些操作时会破坏当前正在执行的代码。实际上,每当您碰巧用gdb挂起它时,bash几乎肯定会等待其子进程完成。
Adrian Pronk

5

由于该命令仍在屏幕上运行,因此其父项bash不会重新读取任何历史记录,因此:

  • 重新连接到屏幕
  • ^Zup arrow
  • 红利:将命令包装在单引号中(使用^A^A- 导航(因为screen(1)-和^E)),然后执行echo +重定向到文件中
  • fg 追求命令执行

有一些警告,但这在大多数情况下都足够有用。


是的,甚至杀死它并按up。尽管您必须确信它会再次毫无问题地重新启动,但是如果不重新启动,则无论如何在重启后都会遇到相同的问题。您只需选择停机时间不会成为问题的时刻。
Matthieu Napoli 2014年

0

我知道您找到了自己的答案,但是有理由不能执行以下操作:

(set -x; for f in 1 2 3 4 ; do  echo "$f"; sleep $f; done)

也许您不能将实际作业的输出与bash显示当前正在执行的行的输出混合在一起。

另外,FWIW,如果您更喜欢冗长,set -o xtrace

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.