簡體   English   中英

使用awk或sed合並/打印與模式匹配的行(單一行嗎?)

[英]Using awk or sed to merge / print lines matching a pattern (oneliner?)

我有一個包含以下文本的文件:

subject:asdfghj
subject:qwertym
subject:bigger1
subject:sage911
subject:mothers
object:cfvvmkme
object:rjo4j2f2
object:e4r234dd
object:uft5ed8f
object:rf33dfd1

我希望使用awk或sed達到以下結果(因為oneliner會是一個獎勵![Perl oneliner也可以接受]):

subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1

我想將匹配“主題”和“對象”的每一行按列出的順序組合在一起,並用逗號分隔。 我可以看看用awk,sed或perl完成的示例嗎? (如果可能的話,最好是單線嗎?)

我已經嘗試了awk的一些用法來執行此操作,但我仍在學習應該添加:

awk '{if ($0 ~ /subject/) pat1=$1; if ($0 ~ /object/) pat2=$2} {print $0,pat2}'

但是沒有按照我的意願去做! 所以我知道我的語法錯誤。 如果我看到一個對我有很大幫助的示例,那么我可以學習。

不是perl或awk,而是更容易。

$ pr -2ts, file
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1

說明

-2 2列

t忽略打印​​標題(文件名,日期,頁碼等)

s,使用逗號作為列分隔符

我會在perl這樣做:

#!/usr/bin/perl

use strict;
use warnings;

my @subjects;
while ( <DATA> ) { 
    m/^subject:(\w+)/ and push @subjects, $1; 
    m/^object:(\w+)/ and print "subject:",shift @subjects,",object:", $1,"\n";
}


__DATA__
subject:asdfghj
subject:qwertym
subject:bigger1
subject:sage911
subject:mothers
object:cfvvmkme
object:rjo4j2f2
object:e4r234dd
object:uft5ed8f
object:rf33dfd1

減少到一個班輪,這將是:

perl -ne '/^(subject:\w+)/ and push @s, $1; /^object/ and print shift @s,$_' file

greppaste和流程替換

$ paste -d , <(grep 'subject' infile) <(grep 'object' infile)
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1

由於進程替換( <( ) ),這會將grep 'subject' infilegrep 'object' infile的輸出視為文件,然后將結果與paste一起paste ,使用逗號作為分隔符(由-d ,表示)。

sed

想法是讀取所有主題行並將其存儲在容納空間中,然后針對每條對象線獲取容納空間,獲取適當的主題並將其余主題線放回容納空間中。

首先是無法閱讀的單線:

$ sed -rn '/^subject/H;/^object/{G;s/\n+/,/;s/^(.*),([^\n]*)(\n|$)/\2,\1\n/;P;s/^[^\n]*\n//;h}' infile
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1

-r用於擴展的正則表達式(不轉義括號, +| ),並且-n默認情況下不打印。

擴展,更易讀和解釋:

/^subject/H         # Append subject lines to hold space
/^object/ {         # For each object line
    G               # Append hold space to pattern space
    s/\n+/,/        # Replace first group of newlines with a comma

    # Swap object (before comma) and subject (after comma)
    s/^(.*),([^\n]*)(\n|$)/\2,\1\n/

    P               # Print up to first newline
    s/^[^\n]*\n//   # Remove first line (can't use D because there is another command)
    h               # Copy pattern space to hold space
}

備注:

  • 第一次獲取保留空間時,它以換行符開頭( H一個),因此,用逗號分隔的換行符替換了一個或多個換行符,因此\\n+ :第一次是兩個換行符,一個用於其余的部分。
  • 要將主題部分的末尾錨定在交換中,我們使用(\\n|$) :換行符或模式空間的末尾–這是為了使交換也位於最后一行,而我們沒有模式空間末尾的換行符。
  • 這適用於GNU sed。 對於MacOS中的BSD sed,需要進行一些更改:
    • -r選項必須由-E代替。
    • 右括號前必須有一個多余的分號: h;}
    • 要在替換字符串中插入換行符(交換命令),我們必須將\\n替換為'$'\\n'''"$(printf '\\n')"'

由於您專門要求“單一”,我認為簡潔對您而言比清晰重要得多,因此:

$ awk -F: -v OFS=, 'NR>1&&$1!=p{f=1}{p=$1}f{print a[++c],$0;next}{a[NR]=$0}' file
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1

暫無
暫無

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

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