如何编写将重写以下内容的sed
(或awk
,或两者):
echo 'v100 v201 v102 v300 v301 v500 v999 v301' | sed/awk ...
到这个输出:
v1 v2 v3 v4 v5 v6 v7 v5
即每个后续vx
都被重写以开始,v1...vn
并且在v
序列中使用相同的位置(即v301
)v
应该应用相同的(如中v5
)。
旁注:示例输入序列显示了所有可能的可能性(即重复、无序的原始数据、原始数字的跳跃)。
您是可以回答这个问题的 sed 或 awk 专家吗?
与
perl
:v\d+
匹配v
后跟一个或多个十进制数字。\K
afterv
重置匹配部分的开头,保留K
其左侧的内容, thev
,以便仅替换数字序列s
。e
标志导致替换被视为被评估以产生替换的代码。e
在该代码中,$&
包含匹配的部分。A // B
是OR的一种形式,扩展为A
ifA
已定义,B
否则(与之相反A || B
,扩展为A
ifA
解析为真值,B
否则)。//=
是对应的赋值形式。所以A //= B
是if (defined(A)) {A} else {A = B}
.请注意,
$seen
哈希表在这些数字的字符串值上建立索引,依此类推v2 v02 v002
,您将得到v1 v2 v3
,2
并且02
是002
彼此不同的字符串。您可以替换$&
为0+$&
规范化数字(010 被视为 10,而不是八进制 8),以便获得v1 v1 v1
上面的示例。或者,您可以s{v0*\K\d+}{$seen{$&} //= ++$n}ge
保留前导0
s 并v1 v01 v001
改为 get 。例如,为了避免替换
v1
找到的,您可以在匹配 ( )的两侧rev1sion
添加一些单词b
oundary 正则表达式运算符。\bv\K\d+\b
或者仅替换以空格分隔的单词(v1.2
例如不理会),为非白色步调添加一些负面的环顾四周: .S
(?<!\S)v\K\d+(?!\S)
使用
awk
:这将遍历每个输入行的所有字段并重新分配它。重新分配的值
v
后面是 counter 的下一个值n
,除非该字段的值以前曾见过,在这种情况下,它的新值将与之前给出的该字段的值相同。最后
1
的 触发修改行的输出。测试:
awk
仅在与正则表达式匹配时修改字段的替代命令^v[0-9]+$
:或者,跨多行格式化以提高可读性:
GNU 实现
awk
支持RS
被定义为正则表达式,并在RT
特殊变量中记录它匹配的内容。因此,使用它,您可以执行以下操作:请注意,它会替换所有出现的
v
后跟数字,即使是在诸如 inrev1.2
或之类的单词中找到的那些rev0lution
。就像我的 perl 方法一样,如果数字可能是零填充的,您可能需要调整它。如果您的输入仅包含后跟数字的“v”字符串,并且您可以使用空格分隔的输出,则此 perl 脚本可以执行您想要的操作:
perl 的
-n
选项遍历输入的每一行(类似于sed -n
脚本),并-l
自动从输入行的末尾截取换行符并将它们添加回打印语句。该
while (/(v\d+)/g)
循环迭代(并捕获)每个输入行中$1
匹配的所有字符串。v\d+
如果该匹配项之前没有出现过,则增加计数器并将其添加到 %seen 哈希中。然后push
(即添加到末尾)一个名为@line
. 在while 循环结束后(即处理完输入行之后),打印@line 数组,每个元素之间有一个空格字符。对于每个输入行,@line 数组都重置为空。如果您还希望为每个输入行重置编号 (
$i
) 和哈希,请取消注释该行之前的两行:%seen
while(...)
仅限 GNU awk: