Unix 在Oracle Solaris 11上关闭控制台并打开新控制台后,将.jar应用程序输出流抓取到控制台
在Oracle Solaris 11控制台上,当发出Unix 在Oracle Solaris 11上关闭控制台并打开新控制台后,将.jar应用程序输出流抓取到控制台,unix,console,solaris,Unix,Console,Solaris,在Oracle Solaris 11控制台上,当发出ps-ef | grep java命令时,我可以看到正在运行一些java进程PID,该进程PID在其他控制台窗口上启动,然后它(控制台窗口)关闭(.jar应用程序输出可见)。是否可以在不重新启动.jar文件的情况下再次获取应用程序输出 应用程序是这样启动的(作为root用户): 在这种情况下,将输出写入文件不是一个选项。是的,您可以这样做,但它涉及到一些使用gdb的疯狂技能。下面是在Linux中如何做到这一点,我相信在Solaris中也可以做到
ps-ef | grep java
命令时,我可以看到正在运行一些java进程PID,该进程PID在其他控制台窗口上启动,然后它(控制台窗口)关闭(.jar应用程序输出可见)。是否可以在不重新启动.jar文件的情况下再次获取应用程序输出
应用程序是这样启动的(作为root
用户):
在这种情况下,将输出写入文件不是一个选项。是的,您可以这样做,但它涉及到一些使用gdb的疯狂技能。下面是在Linux中如何做到这一点,我相信在Solaris中也可以做到这一点(因为它有gdb,并且它有我将进一步使用的所有需要的系统调用) 标准流有3个文件描述符:
- 标准偏差:0
- 标准:1
- 标准:2
$ okular &
然后关闭这个终端。这只是为了模拟你的情况joe 27599 2.2 0.9 515644 73944 ? S 23:46 0:00 okular
lrwx------ 1 joe joe 64 Feb 18 23:46 0 -> /dev/pts/0 (deleted)
lrwx------ 1 joe joe 64 Feb 18 23:46 1 -> /dev/pts/0 (deleted)
lrwx------ 1 joe joe 64 Feb 18 23:46 2 -> /dev/pts/0 (deleted)
所以“okular”PID是27599joe 27599 2.2 0.9 515644 73944 ? S 23:46 0:00 okular
lrwx------ 1 joe joe 64 Feb 18 23:46 0 -> /dev/pts/0 (deleted)
lrwx------ 1 joe joe 64 Feb 18 23:46 1 -> /dev/pts/0 (deleted)
lrwx------ 1 joe joe 64 Feb 18 23:46 2 -> /dev/pts/0 (deleted)
您会看到所有3个流都被删除$ gdb -p 27599 /usr/bin/okular
在gdb内部执行下一步操作:
(gdb) p close(2)
(gdb) p creat("/tmp/okular_2", 0600)
(gdb) detach
(gdb) quit
这里我们调用了两个系统调用:
- close(),关闭进程流的stderr文件
- create(),为流程的stderr流创建新文件
$ tail -f /tmp/okular_2
如果需要恢复stdin流,可以将其附加到管道(FIFO)文件,请参阅详细信息。是的,可以使用Solaris本机工具监视任何进程输出 一种方法是使用
dtrace
,它允许跟踪进程,即使它们已经被调试器或类似工具捕获
此dtrace
脚本将显示给定的进程stdout
:
#!/bin/ksh
pid=$1
dtrace -qn "syscall::write:entry /pid == $pid && arg0 == 1 /
{ printf(\"%s\",copyinstr(arg1)); }"
您应该将java应用程序的进程id作为其第一个参数传递给trace,例如,$(pgrep-f“java-jar SomeFile.jar”)
如果要跟踪stderr
vsstdin
,请将arg0==1
替换为arg0==2
如果要查看不可显示的字符(八进制),可以使用此稍加修改的版本:
#!/bin/ksh
pid=$1
dtrace -qn "syscall::write:entry /pid == $pid && arg0 == 1 /
{ printf(\"%s\",copyinstr(arg1)); }" | od -c
另一种本地方法是使用truss
命令。以下脚本将显示从进程到任何文件描述符的所有写入,并将包括stdout
和stderr
的完整详细跟踪(3799是您的目标进程pid):
dtrace: 桁架:
试图在Solaris11上查找
gdm
。我想我需要先安装这个软件包。只有它是gdb,不是gdm:)是的,你可以从这里安装它(对于Solaris):。或者您可以手动生成它:。实际上,您可以使用任何调试器,而不仅仅是gdb。只需确保它能够连接到进程并执行系统调用。语法可能会有所不同,所以我建议您使用gdb,因为我已经测试了我提供的过程(使用gdb),它可以工作。我尝试过这样:gdb-p 3228 someApp.jar
,但在一些结果中,我发现这行代码:“someApp.jar”:不是可执行格式:无法识别的文件格式。。很奇怪,你可以用“gdb-P3228”。如果您想向gdb(用于符号)提供可执行二进制文件,那么应该提供“java”可执行文件的路径,而不是jar文件的路径。好的,现在我得到了以下输出:附加到进程3228 Retry#1:Retry#2:Retry#3:Retry#4:[New lwp1]0xff27bf0a in??()(gdb)
。似乎不是很有用的信息。。(总共8行-很难在注释中格式化:)当然-PID 3228只是一个例子。我得到了这个错误:dtrace:invalid probe specifier syscall::write:entry/3799==&&arg0==1/{printf(%s,copyinstr(arg1));}:靠近“&&&&”
对不起,我不清楚。此脚本期望一个名为pid的shell变量包含要跟踪的程序的进程id。还有一个问题是双引号。用经过测试的方式编辑回复。是的,它工作正常,但我看到文本输出中有很多错误。看起来像终端窗口中的白色方块…是什么让您断言这些是错误?这些方块可能只是JVM或终端仿真器无法表示的非ASCII字符。您可以通过管道将脚本输出到od-c
,以查看它们的八进制值。回复再次更新,以另一种方式更新,这也将有助于确定这些字符的确切含义。您有什么理由不跟进目前提供的回复?
#!/bin/ksh
pid=$1
dtrace -qn "syscall::write:entry /pid == $pid && arg0 == 1 /
{ printf(\"%s\",copyinstr(arg1)); }" | od -c
truss -w1,2 -t write -p 3799