我有以下输入(一千行)。我想要一个sed
命令将重复的行与相同的前三个字段合并添加仅不同的领域或删除“不适用”:
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
预期输出:
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2
答案1
sed ':n
s|;N/A;|;|g;$!N
s|^\(\([^;]*;\)\{3\}\)\(.*\)\n\1|\1\3;|;tn
P;D
' <<\IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
LE040A;1;363;(28.5);N/A;SM-1-3
LE040A;1;363;(29.6);N/A;SM-1-4
IN
对于输入中的每个序列,这将继续分支回t
est,仅合并每个序列的尾部。
这是可移植的,但是如果你可以使用的话,写起来会更容易一些-E
扩展正则表达式(就像您可能使用 BSD 或 GNU 版本一样)...
sed -E ':n
s|;N/A;|;|g;$!N
s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn
P;D'
如果您想将所有内容都写在一行上:
sed -Ee:n -e's|;N/A;|;|g;$!N;s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn' -eP\;D
...会起作用,但我从来都不是很喜欢一句台词像那样...
无论如何,第一个的输出是:
输出
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);SM-1-1;(27.4);SM-1-2;(28.5);SM-1-3;(29.6);SM-1-4
还可以移动以 w/ 开头的任何尾随字段SM-
到行尾,并用 分隔每个/
,我相信以下应该有效:
sed -E ':n
s|;N/A;|;|g
s|;(SM-[^;]*)$|/\1|;$!N
s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn
P;D'
顺便说一句,如果您能够更清楚、更具体地了解您的需求,这会变得更容易、更快。对我来说,您似乎不想只合并前三个相同的字段任何两个连续的行,并删除匹配的字段N/A
从任何线,然后移动SM-
字段到尾部任何线。相反,对我来说,你所说的所有这些单独的工作实际上都是一样的,而且你真的想要这样的东西:
- 如果发现输入行包含三个字母数字、分号分隔的字段,然后是一个带括号的浮点字段,后跟另一个冒号分隔符,然后是一个
N/A
领域,我们应该做到以下几点:- 检查下一行是否也与此描述匹配,如果是,则比较当前行和下一行的前三个字段。
- 如果找到匹配项,则仅保留下一行的最后一个字段,然后递归重试。
- 无论如何,始终删除匹配的字段
N/A
,并将最后一个替换;
为/
。
- 无论如何,将剩余的所有内容打印到标准输出。
你看出有什么不同了吗?它是根据单个初始条件执行的一系列任务。如果你能这么清楚,那么你的匹配就不必弥补你处理时间的普遍性。
如果我是正确的,那么以下可以工作:
sed ' \|;N/A;|!b
s||/|;$!N
\|^\(.*(\)\(.*)\)\(.*\)\(\n\1\)\(.*)\)|!P
s||\4\2;(\5\3|;D
' <<\IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
LE040A;1;363;(28.5);N/A;SM-1-3
LE040A;1;363;(29.6);N/A;SM-1-4
IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);(28.5);(29.6)/SM-1-1/SM-1-2/SM-1-3/SM-1-4
...这里是-E
在一条线上...
sed -e'\|;N/A;|!b' -e's||/|;$!N;\|^\(.*(\)\(.*)\)\(.*\)\(\n\1\)\(.*)\)|!P;s||\4\2;(\5\3|;D'
...或在-E
扩展语法...
sed -Ee'\|;N/A;|!b' -e's||/|;$!N;\|^(.*\()(.*\))(.*)(\n\1)(.*\))|!P;s||\4\2(\5\3|;D'
答案2
发射机:
@(repeat)
@ (cases)
@id;@f2;@f3;@val1;@nil;@sm1
@id;@f2;@f3;@val2;@nil;@sm2
@ (do (put-line `@id;@f2;@f3;@val1;@val2;@sm1/@sm2`))
@ (or)
@line
@ (do (put-line line))
@ (end)
@(end)
$ txr data.txr data
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2
答案3
sed -r ':a;N;s!;N/A!!g;s/^(([^;]*;){3})(.*)\n\1/\1\3;/;T;s!^(([^S][^;]*;){3,})(S*SM-[^;]*);(([^S][^;]*;){1,})(.*)!\1\4\3/\6!;ta' inputfile
尽管输出中仅 6 个字段的注释的隐含数学表明只有对,但这是循环版本,匹配时对输出 SM-1-1/SM-1-2 进行了更改。