
我有大量文件,需要取出特定行,然後將取出的資料放入電子表格中。一個例子是我的文件顯示:
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
我們正在做的是建立兩個數組ages
,heights
並將每個匹配行保存到其中。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。Height
Weight
txt
*txt
-w
Age
Ageing
-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()
我已經使用第一列進行了哈希處理並將其放入列表中。