使用 awk 列印新行

使用 awk 列印新行

我有大量文件,需要取出特定行,然後將取出的資料放入電子表格中。一個例子是我的文件顯示:

Name: w

Age: x

Height: y

Weight: z

我只想要年齡、身高和體重,所以我先跑:

grep -E 'Age|Height|Weight' [input file] > output.txt

由於文件數量較多,我的輸出現在看起來像

Age 1
 
Height 1

Weight 1

Age 2

Height 2

Weight 2

etc...

我現在想要的是運行 awk 腳本,以便它可以遍歷我的新 output.txt 文件,首先找到包含“Age”一詞的每一行,然後將其列印出來。一旦完成所有“年齡”的計算,它就會計算身高和體重。我運行了腳本:

awk -F"\t" '/Age/ {print} /Height/ {print}' output.txt >output2.txt

但如果只是像原始輸出檔一樣列印它。我該如何改變它,以便在完成所有年齡的之後,它然後找到高度的?

編輯:

我想要的輸出是文件

1 歲

2歲

高度1

高度2

重量1

重量2

ETC..

澄清一下,年齡 1 是文件 1 中包含「年齡」的行,依此類推。

答案1

預設情況下,awk 僅運行一次文件,按順序運行所有區塊,這就是它為您提供輸出的原因。您可以使用來獲得您想要的行為陣列隨時保存行,同時仍只處理文件一次:

BEGIN {
    AgeIndex = 1
    HeightIndex = 1
}
/Age/ {
    ages[AgeIndex] = $0
    AgeIndex+=1
}
/Height/ {
    heights[HeightIndex] = $0
    HeightIndex+=1
}
END {
    for (x = 1; x < AgeIndex; x++)
        print ages[x] "\n"
    for (x = 1; x < HeightIndex; x++)
        print heights[x] "\n"
}

將其保存到,filter.awk然後運行:

awk -f filter.awk output.txt > output2.txt

得到你想要的輸出:

$ awk -f filter.awk < data
Age 1

Age 2

Height 1

Height 2

我們正在做的是建立兩個數組agesheights並將每個匹配行保存到其中。AgeIndex保存我們到達數組的距離。最後,我們列印我們保存的每一行(以及您想要的額外換行符),首先是所有年齡,然後是所有身高。

陣列最後會將整個檔案保存在記憶體中,因此,如果您的檔案特別大,您必須權衡記憶體使用量,以換取多次遍歷整個檔案的時間。此時,它與任何其他語言的程式本質上是相同的 - 如果您沒有任何特殊原因使用 awk,您可能會更喜歡其他語言。說實話,我想我會建議 - awk 在這裡並沒有給你太多好處。

答案2

gawk

$ awk -F"\t" '
    { a[$1]++ }
    END {
        n = asorti(a,b);
        for (i = 1; i <= n; i++) {
            print b[i];
            if (i%2 == 0) {
                printf "\n";
            }
        }
    }
' output.txt
Age 1
Age 2

Height 1
Height 2

Weight 1
Weight 2

答案3

我認為空行不是您實際文件的一部分,或者至少您不關心它們。如果是這樣,您所需要的只是sort

$ cat output.txt
Age 1
Height 1
Weight 1
Age 2
Height 2
Weight 2

$ sort output.txt
Age 1
Age 2
Height 1
Height 2
Weight 1
Weight 2

但是,除非您的檔案太大而無法儲存在記憶體中,否則一步完成整個操作可能會更簡單:

grep -whE 'Age|Height|Weight' *txt | sort > outfile

上面的命令將在目前目錄 ( ) 中搜尋名稱以或結尾Age的所有檔案。意思是「只匹配整個單字」(例如,不匹配),這是需要的,因為如果沒有它,當給出多個輸入檔案時,檔案名稱將與匹配行一起列印。它啟用了擴展正則表達式,為我們提供了 OR。HeightWeighttxt*txt-wAgeAgeing-h-E|

筆記: 如果由於某種原因,您確實想要每個條目之間有額外的空白行(這不是您的grep命令會產生的),您可以使用以下命令添加它:

grep -whE 'Age|Height|Weight' *txt | sort | sed 's/$/\n/'

例子

$ for i in {1..3}; do echo -e "Name $i\nAge $i\nHeight $i\nWeight $i" > $i.txt; done
$ for f in *txt; do echo " -- $f --"; cat $f; done
 -- 1.txt --
Name 1
Age 1
Height 1
Weight 1
 -- 2.txt --
Name 2
Age 2
Height 2
Weight 2
 -- 3.txt --
Name 3
Age 3
Height 3
Weight 3

$ grep -whE 'Age|Height|Weight' *txt | sort
Age 1
Age 2
Age 3
Height 1
Height 2
Height 3
Weight 1
Weight 2
Weight 3

無論如何,即使sort不會為你削減它,我也會在 Perl 中做這種事情,而不是awk(這是假設你想要額外的空行,但你可能不想要):

$ perl -ane '$k{$F[0]}.=$_."\n" if /./; 
    END{print $k{$_},"\n" for sort keys (%k)}' output.txt 
Age 1

Age 2


Height 1

Height 2


Weight 1

Weight 2


 

如果您不需要的話,可以透過它head -n -2來刪除最後兩行空行。

答案4

python這個問題的解決方案:

from collections import defaultdict
f = open("output.txt", "r")
d = defaultdict(list)
for line in f:
   line = line.strip()
   if line != '':
     arr = line.split(" ")
     d[arr[0]].append(arr[1])
print d.items()

我已經使用第一列進行了哈希處理並將其放入列表中。

相關內容