搜索模式并在同一行打印

搜索模式并在同一行打印

我有一个以下格式的大 .txt 文件

  Pin name="AR_OP" status="f" 
      Pref x=997.6800 y=2327.0400 side=N width=0.0400 depth=0.3750 /
      Layer id=1 
--
  Pin name="AW_OP" status="f" 
      Pref x=997.6800 y=2327.0400 side=S width=0.0400 depth=0.3750 /
      Layer id=2 

我想要的输出如下:

Pin name="AR_OP" side=N
Pin name="AW_OP" side=S

对于我想要搜索的每个部分引脚名称并对应于我想要的引脚名称在同一行。任何人都可以帮忙。

答案1

将所有空格替换为换行符,然后拉出以Pin、 或以 或 开头的name=side=。这给了我们三组一组的线。将每组三行重新格式化为一行,并以空格作为分隔符。

$ tr ' ' '\n' <file | grep -e '^Pin$' -e '^name=' -e '^side=' | paste -d ' ' - - -
Pin name="AR_OP" side=N
Pin name="AW_OP" side=S

这假设所有值都不包含嵌入空格。


假设该文档最初是一些 XML 文档,如下所示:

<?xml version="1.0"?>
<root>
  <Pin name="AR_OP" status="f">
    <Pref x="997.6800" y="2327.0400" side="N" width="0.0400" depth="0.3750"/>
    <Layer id="1"/>
  </Pin>
  <Pin name="AW_OP" status="f">
    <Pref x="997.6800" y="2327.0400" side="S" width="0.0400" depth="0.3750"/>
    <Layer id="2"/>
  </Pin>
</root>

那么数据会更好地从使用 XML 感知工具而不是使用文本处理工具进行后处理变体。

例如,

xmlstarlet select --template \
    --match  '//Pin' --output 'Pin' \
    --output ' name="' --value-of '@name'      --output '"' \
    --output ' side="' --value-of 'Pref/@side' --output '"' \
    -nl file

这用于xmlstarlet查找Pin输入文档中的所有节点。然后它迭代这些,以请求的格式输出它们的name属性和Pref子节点的属性。side

类似的方法xq,一个围绕众所周知的jqJSON 解析器的 XML 解析器包装器:

xq -r '.root.Pin | map("Pin name=\"\(."@name")\" side=\"\(.Pref."@side")\"")[]' file

答案2

假设 的值side始终包含至少一个大写字符:

awk '{
    if (match($0, /Pin name="[^"]+"/)) {
        printf "%s ", substr($0, RSTART, RLENGTH)
        next
    }
    if (match($0, /side=[A-Z]+/)) {
        printf "%s\n", substr($0, RSTART, RLENGTH)
    }
}' file

这仅输出匹配的部分加上空格或换行符。

答案3

使用perl:

$ perl -lne 'if (/^\s*(Pin name="[^"]*").*/) {
               $pin = $1;
               $_ = <>;
               if (/(side=.)/) {
                 $side = $1;
                 printf "%s %s\n", $pin, $side;
               }
             }' input.txt
Pin name="AR_OP" side=N
Pin name="AW_OP" side=S

用英语讲:

如果当前行匹配,Pin name"[^"]*"则使用捕获组 ( $1) 提取它并将其存储在变量 中$pin,然后读取下一行 ( $_ = <>;)。如果它包含“side=.”然后将其提取到变量中$side并打印 $pin 和 $side 并在它们之间留一个空格。所有其他输入行都将被忽略。

这是另一种变体:

$ perl -lne 'if (/^\s*(Pin name="[^"]*").*/) {
               $pin=$1;
               ($side = <>) =~ s/^.*(side=.).*/\1/;
               printf "%s %s", $pin, $side if $side =~ /side=/
             }' input.txt 
Pin name="AR_OP" side=N
Pin name="AW_OP" side=S

用英语讲:

如果当前行与“Pin name...”匹配,则将其提取并保存在变量 $pin 中,然后将下一行读($side = <>)入变量$side并修改 $side 以删除除“side=”之外的所有内容。 ( =~ s/^.*(side=.).*/\1/;),然后将它们都打印出来如果 $side包含/side=/.


顺便说一句,该($side = <>) =~ s/^.*(side=.).*/\1/;行是一个有用的 perl 习惯用法的示例,用于分配变量,然后立即使用替换操作修改它(s///. tr///也可以)。它相当于两个语句:$side=<>将下一行读入 $side,然后$side =~ s/^.*(side=.).*/\1/;修改 $side。

赋值周围的括号很重要,否则变量将包含成功/失败或替换操作的计数(但前提是赋值的右侧=是可修改的变量 - 如果不是,如果是一些不可修改的东西,比如文件句柄,那么它就是一个语法错误)。

答案4

使用:

适用于文本文件(原样) 和或者:

xidel -e '//Pin/concat(
    "Pin Name=&quot;", @name, "&quot; side=&quot;", ./Pref/@side, "&quot;"
)' file.html

输出

Pin Name="AR_OP" side="N"
Pin Name="AW_OP" side="S"

相关内容