我有一个以下格式的大 .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
,一个围绕众所周知的jq
JSON 解析器的 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。
赋值周围的括号很重要,否则变量将包含成功/失败或替换操作的计数(但前提是赋值的右侧=
是可修改的变量 - 如果不是,如果是一些不可修改的东西,比如文件句柄,那么它就是一个语法错误)。