将文本文件中的行与匹配的第一个字段进行匹配的快速简洁方法是什么?
示例输入:
a|lorem
b|ipsum
b|dolor
c|sit
d|amet
d|consectetur
e|adipisicing
e|elit
期望的输出:
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit
期望的输出,替代方案:
b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit
我可以想象很多方法来写这个,但我怀疑有一个聪明的方法来做,例如,使用sed,awk等。我的源文件大约是0.5 GB。
这里有一些相关问题,例如“awk | merge line on the basis of field matching”,但是其他问题会将太多内容加载到内存中。我需要一种流媒体方法。
答案 0 :(得分:3)
对于固定宽度字段,您可以使用uniq
:
$ uniq -Dw 1 file
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit
如果您没有固定宽度字段,则此处有两个awk
解决方案:
awk -F'|' '{a[$1]++;b[$1]=(b[$1])?b[$1]RS$0:$0}END{for(k in a)if(a[k]>1)print b[k]}' file
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit
awk -F'|' '{a[$1]++;b[$1]=b[$1]FS$2}END{for(k in a)if(a[k]>1)print k b[k]}' file
b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit
答案 1 :(得分:3)
这是一种只需记住上一行的方法(因此需要对输入文件进行排序)
awk -F \| '
$1 == prev_key {print prev_line; matches ++}
$1 != prev_key {
if (matches) print prev_line
matches = 0
prev_key = $1
}
{prev_line = $0}
END { if (matches) print $0 }
' filename
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit
替代输出
awk -F \| '
$1 == prev_key {
if (matches == 0) printf "%s", $1
printf "%s%s", FS, prev_value
matches ++
}
$1 != prev_key {
if (matches) printf "%s%s\n", FS, prev_value
matches = 0
prev_key = $1
}
{prev_value = $2}
END {if (matches) printf "%s%s\n", FS, $2}
' filename
b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit
答案 2 :(得分:1)
使用awk:
awk -F '|' '!($1 in a){a[$1]=$2; next} $1 in a{b[$1]=b[$1] FS a[$1] FS $2}
END{for(i in b) print i b[i]}' file
d|amet|consectetur
e|adipisicing|elit
b|ipsum|dolor
答案 3 :(得分:1)
这可能适合你(GNU sed):
sed -r ':a;$!N;s/^(([^|]*\|).*)\n\2/\1|/;ta;/^([^\n|]*\|){2,}/P;D' /file
这将在模式空间中读取2行,然后检查两行中的键是否相同。如果是这样,它将删除第二个键并重复。如果不是,则检查第一行中是否存在两个以上的字段,如果是,则将其打印出来然后将其删除,否则只删除第一行。
答案 4 :(得分:0)
$ awk -F'|' '$1 == prev {rec = rec RS $0; size++; next} {if (size>1) print rec; rec=$0; size=1} {prev = $1} END{if (size>1) print rec}' file
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit
$ awk -F'|' '$1 == prev {rec = rec FS $2; size++; next} {if (size>1) print rec; rec=$0; size=1} {prev = $1} END{if (size>1) print rec}' file
b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit