如何在 shell 脚本中使用 awk 处理字符串

How to process string in using awk in shell script

我对 shell 脚本编写还很陌生,必须围绕它完成很多任务。我正在尝试尽可能快地学习,但有时 shell 脚本使任务看起来非常简单,而在其他时候它只是在玩弄我。而我现在面临着类似的情况。 我有一个命令给我这样的输出。

 File                  Dependents
  ----------------------------------------------------------------------------
<File> is a requisite of <Dependents>
Path: /usr/lib/obj
  Java 1.0.0.0          analysis 0.0.0.2
                        runtime 1.2.0.0
                        client 1.2.0.0
                        framework 6.1.9.100
                        sguide 1.9.10.0
                        sysmgt 6.1.9.100
                        dsm 6.1.9.200

Path: /etc/obj
  Java 1.0.0.0          analysis 1.2.0.2
                        runtime 2.0.0.0
                        client3 6.1.9.0
                        sysmgt 6.1.9.0
                        dsm2 6.1.9.0

现在我想将依赖项列表放入一个数组中以供进一步处理。这是我目前能做的:

<command> | cut -f1 | grep '[a-z]' | grep -v File | grep -v : | awk '{ print }'

输出为:

Java<<< I want this to be analysis
runtime
client
framework
sguide
sysmgt
dsm

Java<<< want this to be analysis
runtime
client3
sysmgt
dsm2

我必须在两个单独的数组中捕获这两个列表。

有人可以帮助我以一种优雅的方式实现这个输出吗?我不想用涉及很多条件和比较的蛮力方法来破坏这段代码。

您可以先删除带有 Java 的子字符串来修复您的解决方案:

command | sed 's/Java [^ ]*//' | cut -f1 | grep '[a-z]' | grep -v File | grep -v : | awk '{ print }'

当你使用awk的时候,可以更好的发挥出awk的全部实力。只是说你想要打印任何带有数字的行的倒数第二个字段:

command | awk '/[0-9]/ { print $(NF-1) }'

这比尝试使用 sed 更好(您有制表符或空格吗?)

command | sed -n '/[0-9].[0-9]/ s/^.* \([^ ]*\) .*//p'

一个有趣的解决方案是使用 rev 还原文本。这样cut可以找到第二个字段。

command | grep '[0-9].[0-9]' | rev | cut -d " " -f2 | rev

对于只阅读最后一行的人,我将重复awk解决方案:

command | awk '/[0-9]/ { print $(NF-1) }'

awk 救援!

$ arr1=$(command ... | awk -v c=1 '!NF{f=0} f && s==c{print } /Java/{f=1; s++; if(s==c) print $(NF-1)}')

$ arr2=$(command ... | awk -v c=2 '!NF{f=0} f && s==c{print } /Java/{f=1; s++; if(s==c) print $(NF-1)}')

$ echo $arr1
analysis runtime client framework sguide sysmgt dsm

$ echo $arr2
analysis runtime client3 sysmgt dsm2

如果您 运行 命令一次并将结果分成两个数组,可能会更好。

说明

awk -v c=1 set awk variable c to 1 (describes group instance number)

'!NF{f=0} if there are no fields (empty line) reset f

f && s==c{print } if f is set and counter equals to c print the first field

/Java/{f=1; s++; when pattern matched to Java, set f and increment counter and ...if(s==c) print $(NF-1)}' if counter matches c print the penultimate field.