[英]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
grep
, paste
和流程替換
$ 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' infile
和grep '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|$)
:換行符或模式空間的末尾–這是為了使交換也位於最后一行,而我們沒有模式空間末尾的換行符。 -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.