簡體   English   中英

命令行以匹配具有匹配的第一字段(sed,awk等)的行

[英]Command line to match lines with matching first field (sed, awk, etc.)

什么是快速且簡潔的方式來匹配文本文件中具有匹配的第一字段的行。

輸入樣例:

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 |基於字段匹配的合並行 ”,但是另一個問題將過多的內容加載到內存中。 我需要一種流方法。

對於固定寬度的字段,可以使用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

這是一種方法,您只需記住上一行(因此需要對輸入文件進行排序)

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

使用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

這可能對您有用(GNU sed):

sed -r ':a;$!N;s/^(([^|]*\|).*)\n\2/\1|/;ta;/^([^\n|]*\|){2,}/P;D' /file

這會將2行讀入模式空間,然后檢查兩行中的鍵是否相同。 如果是這樣,它將刪除第二個鍵並重復。 如果不是,它將檢查第一行中是否存在兩個以上的字段,如果有,則將其打印出來,然后將其刪除,否則它將僅刪除第一行。

$ 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM