我正在尝试提取命令输出的参数。目前,我有这个:
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的命令。
最佳答案
通常,回答外壳程序形式为“如何解析...的输出?”的第一步。是要问另一个问题:“如何在不解析命令输出的情况下获取[此信息]?”。
当然,几乎总是需要某种类型的解析,但是如果您可以将其简化为在某些定界符字符串上的可靠拆分,那么您就可以解决问题,因为有很多方法可以在定界符处拆分字符串。 (请参阅下面的其中一项。)
注意:此答案的其余部分假定使用软件包procps-ng中的bash
,Gnu awk
和ps
进行合理标准的Linux安装。它可以很容易地适应其他环境,但是细节会使叙述变得过于复杂。ps
命令带有一组不错的输出选项,使自定义命令的输出非常容易。例如,如果您想查看正在运行的进程的所有命令行,而没有任何其他令人困惑的数据,则可以尝试以下操作:
ps -e -ops=,cmd=
这将打印系统上所有进程的pid和命令行。 (如果愿意,可以使用
-ea
,很多人都可以使用。使用ps
的procps-ng版本,没有任何区别。)输出规范
-o
由逗号分隔的字段列表组成(其名称在标有“标准格式规范”的man ps
中记录)。每个字段名称后面都可以有一个=和一些文本(不能包含逗号);文本用于标题行,即第一行输出。使用just =不带文本表示该列没有标题,并且如果没有列具有标题,则不打印标题行。这使“解析”更加容易。ps
可以打印的许多字段很容易解析,因为它们不能包含空格。实际上,手册页列出了一些可以包含空格的字段:以下用户定义的格式说明符可能包含空格:args,cmd,comm,命令,fname,ucmd,ucomm,lstart,bsdstart,start
并且该列表实际上比不同说明符的实际数量大得多,因为
args
和command
是cmd
的别名(显示整个命令行),而ucmd
和ucomm
是< cc>-显示可执行文件的名称。这些字段可能包含空格甚至是换行符,这一事实无疑使解析变得复杂。对于命令行参数,它实际上使解析变得不可能,因为无法区分包含空格的命令行参数和两个连续的命令行参数之间的空格。理想情况下,我们需要一种确定的方法来为每个进程提取命令行参数。
虽然我们无法从
comm
获取此信息,但是我们可以转到ps
使用的信息源:ps
文件系统。特别是,对于任何pid,“文件” /proc
包含命令行组件,每个组件以NUL字节终止。例如,我的/proc/PID/cmdline
流程如下所示:$ 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字节,因此这是完全明确的。
我们可以通过简单地遍历
init
目录来提取所有正在运行的进程的所有命令行:cat /proc/[1-9]*/cmdline
(我使用了
/proc
而不是[1-9]*
,因为*
文件系统中还有其他子目录。)但这会产生以NUL分隔的记录的换行分隔的行,对于大多数实用程序而言,这不是最方便的格式。 (此外,它还引入了歧义,因为换行符可能是参数的一部分。)幸运的是,Gnu
/proc
很乐意将NUL用作记录分隔符,并具有正则表达式匹配功能。因此,要查找以awk
开头的所有正在运行的进程的所有参数,我们可以使用以下一种代码:awk -v RS='\0' '/^-javaagent:/' /proc/[1-9]*/cmdline
注意:
在上面的描述中,我跳过了几个细节。其中一个是
-javaagent:
仅包含命令行的前4k。由于Java调用通常很长,因此命令行的一部分可能会丢失。但是,由于/proc/PID/cmdline
使用ps
文件系统来获取其显示的信息,因此会遇到相同的问题。我不知道有什么容易的方法。另一个问题是,如果要以某种方式隐藏或重新处理自己的命令行,则正在运行的进程可以修改
/proc
中显示的数据。例如,如果查看-ocmd=
进程的条目,则会看到参数用空格而不是NUL分隔。
关于linux - 解析命令输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50352475/