我有一个长时间运行的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
为我得到的一些答案添加反例。
关于使用
cmdline
under/proc/PID
: 不起作用,至少在我的场景中不起作用。这是一个简单的例子:$ echo $$ 8909 $ while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
在另一个外壳中:
$ cat /proc/8909/cmdline bash
使用
ps -p PID --noheaders -o cmd
同样没用:$ ps -p 8909 --no-headers -o cmd bash
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
也就是说,没有原始命令行的输出,这正是我正在寻找的 - 即
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
.
答案1
我知道我正在抓住救命稻草,但 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脚本,自动化该过程。
答案2
由于该命令仍在屏幕中运行,因此其父 bash 尚未重新读取任何历史记录,因此:
- 重新连接到屏幕
^Z
然后按up arrow
- 奖励:将命令用单引号括起来(使用
^A^A
- 因为 screen(1) - 和^E
)导航并 echo + 重定向到文件中 fg
追求命令执行
虽然有一些警告,但在大多数情况下这已经足够有用了。
答案3
我知道您找到了自己的答案,但是您是否有理由不能这样做:
(set -x; for f in 1 2 3 4 ; do echo "$f"; sleep $f; done)
也许您无法将实际作业的输出与显示当前执行行的 bash 输出混合在一起。
另外,FWIW,如果您喜欢冗长的话,set -o xtrace
.