解析命令的输出

时间:2018-05-15 14:13:38

标签: linux string bash parsing extract

我正在尝试提取命令输出的参数。目前我有这个:

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。

2 个答案:

答案 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

并且该列表实际上比不同说明符的实际数量大得多,因为commandcmducmd的别名 - 显示整个命令行 - 和{{ 1}}和ucommcomm的别名 - 显示可执行文件的名称。

这些字段可能包含空格,甚至是换行符,这一事实肯定会使解析变得复杂。在命令行参数的情况下,它实际上使得解析不可能,因为无法区分包含空格的命令行参数和两个连续的命令行参数,它们之间有空格。理想情况下,我们需要一种为每个进程提取命令行参数的明确方法。

虽然我们无法从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分隔。