arrays - 结合awk命令将搜索的输出显示在一行中

标签 arrays linux bash awk sed

我的意见如下

<connection name="test1" transport="tcp">
<LPort>host1:11111</hostPort>
<hostPort>host1:11111</hostPort>
<abcd> 1234

<connection name="test2" transport="tcp">
<hostPort>host2:22222</hostPort>
<GPort>host1:12111</hostPort>

<connection name="xyz1" transport="tcp">
<hostPort>host3:33333</hostPort>
<FPort>host1:12113</hostPort>
<efgi> 5678

<connection name="xyz2" transport="tcp">
<LPort>host1:12234</hostPort>
<hostPort>host4:4444</hostPort>

我希望我的输出如下:
test1  host1 1111
test2  host2 2222
xyz1   host3 3333
xyz2   host4 4444

把这个拿出来,我就是这么做的,而且很管用。但在我看来,必须有一种更好、更简单的方法来实现它,我没有包括整个逻辑(数组);但是当我有多个
在一个文件中搜索,它就会工作。我试图使用&&command组合awk命令,但失败了。
下面是我的代码和逻辑的一部分
1)我把文件分类
2)去掉多余字符,用sed替换为空格
3)我获取想要的值并使用awk分配给数组值
请注意,我没有包括其余的逻辑(但它工作)
简言之,我做了一个while循环,然后将值赋给2或3个数组,并将它们打印在同一行以获得所需的输出
cat file  | grep -A5 connection  | sed s'/[:="><]/ /g' | awk '/name/ {print $3}'
cat file | grep -A5 connection  | sed s'/[:="><]/ /g' | awk '/hostPort/ {print $2 " " $3}'

如果可能,请提供一个替代解决方案,不涉及使用sed/awk或任何其他方式将搜索条件存储在数组中?
如果您可以提供解决方案,请提供每个选项的详细信息;如果您可以的话。
谢谢你

最佳答案

必须提醒的是:假设您的输入是格式良好的XML,那么使用XML解析器将提供一个更健壮的解决方案(见底部)。
以下是一个实用程序awk解决方案:

awk -v RS= -F '<connection name="|<hostPort>' '
  {
    sub(/".*/, "", $2)
    split($3, tokens, /[:<]/)
    printf "%-6s %s %s\n", $2, tokens[1], tokens[2]
  }
' file

-v RS=告诉awk按段落将输入拆分为记录,其中段落是一段非空行。
-F '<connection name="|<hostPort>'通过出现<connection name="或(|<hostPort>将每个段落拆分为字段,以便感兴趣的数据位于第2和第3个字段的开头($2$3)。
sub(/".*/, "", $2)从字段2中删除第一个"之后的所有内容,实际上只留下连接名。
split($3, tokens, /[:<]/)通过出现:<将第三个字段拆分为一个令牌数组,在第一个数组元素中生成主机名,在第二个数组元素中生成端口。
printf "%-6s %s %s\n", $2, tokens[1], tokens[2]打印一个输出行,在连接名中用空格右填充至少6个字符,如在示例输出中所示;如果只想用一个空格分隔输出字段,只需省略-6
可选读取:可在shell脚本中使用的XML解析实用程序(CLIs)
xmllint已预先安装在某些平台上:
macOS/FreeBSD/PC-BSD(可能是其他BSD变体)
一些Linux发行版:Fedora、CentOS
在其他服务器上,可以使用一个包;例如,在Ubuntu上:
sudo apt-get install libxml2-utils
注意:虽然xmllint支持XPath 1.0查询,但它实际上不允许控制输出格式。
按需安装替代方案-优于xmllint
xmlstarlet
xmlstarlet功能强大、灵活,支持多种操作。
macOS:使用brew install xmlstarlet通过Homebrew安装
Linux:很有可能它可以与您平台的包管理器一起安装;例如,在基于Debian的发行版上,如Ubuntu:
sudo apt-get install xmlstarlet
Windows:从sourceforge手动下载并安装。
xidel
要求手动download and installation,但其功率和灵活性弥补了这种不便。
支持Linux、macOS和Windows
下面是与上面列出的3个实用程序进行对比的解决方案。
以下格式良好的XML文档假定包含在xidel中—请注意file元素现在是如何包含在单个顶级<connection>元素中的:
<doc>
  <connection name="test1" transport="tcp">
    <LPort>host1:11111</LPort>
    <hostPort>host1:11111</hostPort>
    <abcd>1234</abcd>
  </connection>

  <connection name="test2" transport="tcp">
    <hostPort>host2:22222</hostPort>
    <GPort>host1:12111</GPort>
  </connection>

  <connection name="xyz1" transport="tcp">
    <hostPort>host3:33333</hostPort>
    <FPort>host1:12113</FPort>
    <efgi>5678</efgi>
  </connection>

  <connection name="xyz2" transport="tcp">
    <LPort>host1:12234</LPort>
    <hostPort>host4:4444</hostPort>
  </connection>
</doc>

<doc>溶液:
xmllint无法控制查询结果的格式需要一个非常重要的xmllinthelper命令:
echo 'cat //connection/@name | //hostPort/text()' | xmllint --shell file | awk -F\" '
  NR % 2 { next }                  # skip separator lines
  NR % 4 == 2 { conn = $2; next }  # save connnection name
  { 
    split($0, tokens, ":")
    printf "%-6s %s %s\n", conn, tokens[1], tokens[2] 
  }
'

awk溶液:
xmlstarlet xmlstarlet子命令通过将选项翻译成场景后的XLST模板来支持非常灵活的提取:
xmlstarlet sel -t  -m '//connection' -v 'str:align(@name, "      ")' \
           -o ' ' \
           -c 'str:replace(hostPort, ":", " ")' -n file

sel溶液:
xidel非常灵活,不仅支持XML,而且支持HTML和JSON。
虽然它不支持XLST,但它支持XQuery,这是一个具有类似XSLT特性的XPath超集,它支持强大的转换。
据我所知,没有填充功能,但是,使用一个-直接-辅助< cc>命令:
xidel file -q --xquery \
  'for $c in //connection return concat($c/@name, " ", replace($c/hostPort, ":", " "))' |
    awk '{ printf "%-6s %s %s\n", $1, $2, $3 }'

也就是说,XQuery甚至支持用户定义的函数,因此您可以编写自己的填充函数:
xidel -q file --xquery '
  declare function pad($s as xs:string?) as xs:string 
  {
    substring(concat($s, "      "), 1, 6)
  }
  for $c in //connection return concat(pad($c/@name), " ", replace($c/hostPort, ":", " "))
'

关于arrays - 结合awk命令将搜索的输出显示在一行中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44213565/

相关文章:

c# - 如何在 C# 中使用 int64 索引对数组的一部分进行排序?

c - 使用指针访问数组和通过指针访问非数组变量之间有什么区别

linux - 没有主编号的设备

linux - 如何 "catch"非零退出代码尽管 "set -e"然后回显错误代码

linux - Bash Shell 脚本嵌套循环的内部循环不起作用

bash - 如何复制使用 grep 找到的文件

python - 如何在一维数组中找到峰

java - C 整数与 Java 读取的字节并集并重新转换为 Java int

java Runtime.getRuntime().exec 无法获取某些命令的输出

linux - "echo"sh 和 bash 输出不同的答案