我正在尝试提取命令输出的参数。目前我有这个:
ps -eaf | grep javaagent
输出是这样的:
-Dweblogic.system.BootIdentityFile=/u06/app/oracle/admin/domains/omservices/servers/profiling03/data/nodemanager/boot.properties -Dweblogic.nodemanager.ServiceEnabled=true -Dweblogic.security.SSL.ignoreHostnameVerification=false -Dweblogic.ReverseDNSAllowed=false -javaagent:/u01/home/app/appdyn/AppDynamics/AppServerAgent/ver4.3.1.5/javaagent.jar -Dappdynamics.agent.applicationName=BFL_PE_Omnichannel -Dappdynamics.agent.tierName=CDLV_Profiling -Dappdynamics.agent.nodeName=profiling03 -Xms3g -Xmx3g -XX:MaxPermSize=756m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/u06/app/oracle/admin/logs/omservices/profiling03/gc.log -XX:-DisableExplicitGC -Djava.net.preferIPv4Stack=true -Dweblogic.MuxerClass=weblogic.socket.NIOSocketMuxer -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/u06/app/oracle/admin/logs/omservices/profiling03/dump -Dweblogic.Stdout=/u06/app/oracle/admin/logs/omservices/profiling03/profiling03.out -Dprofiling-services.configPath=/cyberbank/profiling/v2/config/ -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Log4jLogger -Dprofiling-services.logPath=/u06/app/oracle/admin/logs/omservices/profiling03 -Duser.timezone=GMT-5 -Dweblogic.management.server=t3://ba410018-priv:4065 weblogic.Server
我想提取参数(我对此路径感兴趣):
-javaagent:/u01/home/app/appdyn/AppDynamics/AppServerAgent/ver4.3.1.5/javaagent.jar
我用以下命令做了这个:
ps -eaf | grep javaagent | cut -d " " -f XX
其中" XX"是XX的列。这个命令的问题是进程总是不一样。但是,javaagent将始终处于这个过程中。
简而言之,一些命令允许我在进程X中提取参数javaagent。
答案 0 :(得分:-1)
只要javaagent.jar
路径中没有空格,就可以使用以下内容:
ps -eaf | grep -Eo '-javaagent:[^ ]*'
从-javaagent
选项的开头到排除的下一个空格匹配。使用grep
' -o
标记使其仅返回匹配的部分而不是整行。
答案 1 :(得分:-1)
通常是回答表单的shell问题的第一步"如何解析...的输出?"是问另一个问题"如何在不必解析命令输出的情况下获得[此信息]?"。
当然,某些类型的解析几乎总是必要的,但是如果你可以将它减少到某个分隔符字符串上的可靠拆分,你很可能会把问题舔掉,因为有很多方法可以在分隔符处拆分字符串。 (见下文中的其中一个。)
注意:本回答的其余部分假设使用bash
,Gnu awk
和来自包procps-ng的ps
进行合理标准的Linux安装。它可以很容易地适应其他环境,但细节会使叙述过于复杂。
ps
命令带有一组很好的输出选项,可以很容易地自定义命令的输出。例如,如果您想查看正在运行的进程的所有命令行,而没有任何其他令人困惑的数据,您可以尝试这样做:
ps -e -ops=,cmd=
这将打印系统上所有进程的pid和命令行。 (如果您愿意,可以使用-ea
,很多人都可以使用ps
。使用procps-ng版本的-o
,它没有任何区别。)
输出规范man ps
由逗号分隔的字段列表组成(其名称在ps
中标记为" STANDARD FORMAT SPECIFIERS")中。每个字段名称后面可以跟一个 = 和一些文本(不能包含逗号);文本用于标题行,这是第一行输出。仅使用没有文本的 = 表示该列没有标题,如果没有列有标题,则不会打印标题行。这使得"解析"更容易。
许多可以打印的字段args
都可以轻松解析,因为它们不能包含空格。实际上,该联机帮助页列出了可以包含空格的少数字段:
以下用户定义的格式说明符可能包含空格:args,cmd,comm,command,fname,ucmd,ucomm,lstart,bsdstart,start
并且该列表实际上比不同说明符的实际数量大得多,因为command
和cmd
是ucmd
的别名 - 显示整个命令行 - 和{{ 1}}和ucomm
是comm
的别名 - 显示可执行文件的名称。
这些字段可能包含空格,甚至是换行符,这一事实肯定会使解析变得复杂。在命令行参数的情况下,它实际上使得解析不可能,因为无法区分包含空格的命令行参数和两个连续的命令行参数,它们之间有空格。理想情况下,我们需要一种为每个进程提取命令行参数的明确方法。
虽然我们无法从ps
获取此信息,但我们可以转到ps
使用的信息来源:/proc
文件系统。特别是对于任何pid,"文件" /proc/PID/cmdline
包含命令行组件,每个组件以NUL字节结尾。例如,我的init
流程如下所示:
$ hd /proc/1/cmdline
00000000 2f 6c 69 62 2f 73 79 73 74 65 6d 64 2f 73 79 73 |/lib/systemd/sys|
00000010 74 65 6d 64 00 2d 2d 73 79 73 74 65 6d 00 2d 2d |temd.--system.--|
00000020 64 65 73 65 72 69 61 6c 69 7a 65 00 31 38 00 |deserialize.18.|
0000002f
由于命令行选项不能包含NUL字节,因此这是完全明确的。
我们可以通过简化/proc
目录来提取所有正在运行的进程的所有命令行:
cat /proc/[1-9]*/cmdline
(我使用[1-9]*
代替*
,因为/proc
文件系统中还有其他子目录。)
但是这会生成以NUL分隔的记录的换行符分隔行,这对于大多数实用程序来说不是最方便的格式。 (此外,它重新引入歧义,因为换行可能是参数的一部分。)幸运的是,Gnu awk
很乐意将NUL作为记录分隔符来处理,并且具有正则表达式匹配功能。因此,要查找以-javaagent:
开头的所有正在运行的进程的所有参数,我们可以使用以下单行:
awk -v RS='\0' '/^-javaagent:/' /proc/[1-9]*/cmdline
我在上面的描述中略过了一些细节。其中之一是/proc/PID/cmdline
仅包含命令行的前4k。由于java调用通常很长,因此可能会丢失部分命令行。但是,由于ps
使用/proc
文件系统来获取它显示的信息,因此它会遇到同样的问题。我知道没有简单的方法。
另一个问题是,-ocmd=
中显示的数据可以由正在运行的进程修改,如果它想以某种方式隐藏或重新处理自己的命令行。例如,如果查看chrome
进程的条目,您将看到参数用空格而不是NUL分隔。