我有一個巨大的xz壓縮文本檔案huge.txt.xz,其中有數百萬行,它太大,無法保持未壓縮的狀態(60GB)。
我想從這個巨大的文本檔案中快速過濾/選擇大量的行(約1000行)到一個檔案filtered.txt。例如,要選擇的行數可以在一個單獨的文本檔案select.txt中指定,格式如下:
10
14
...
1499
15858
總的來說,我設想了一個如下的shell命令,其中 "待定 "是我要找的命令:
。
xz -dcq huge.txt.xz | "TO BE DETERMINED" select.txt > filtered.txt
我設法從一個密切相關的問題中找到了一個awk程式,它幾乎可以完成這項作業 - 唯一的問題是它需要一個檔案名,而不是從stdin讀取。不幸的是,我并不真正了解awk腳本,也不了解足夠的awk來改變它在這種情況下的作業方式。
這就是現在的作業,缺點是有一個60GB的檔案躺在那里,而不是流媒體:
這就是現在的作業。
xz -dcq huge.txt.xz > huge.txt
awk '!firstfile_proceed { nums[1]; next }
(FNR in nums)' select.txt firstfile_proceed=1 > filtered.txt
uj5u.com熱心網友回復:
與OP目前的想法保持一致:
xz -dcq huge.txt.xz | awk '!firstfile_proceed { nums[1]; next } (FNR in nums)' select.txt firstfile_proceed=1 -
這里的-(在行尾)告訴awk從stdin中讀取(在這個例子中是來自xz的輸出,它被輸送到awk呼叫)。
另一種方法可以做到這一點(取代上述所有的代碼):
awk '
FNR==NR { nums[1]; next } # 處理第一個檔案
FNR in nums # 處理后續檔案
' select.txt <(xz -dcq huge.txt.xz)
評論已被洗掉,并被削減為一個 "單行本":
添加一些邏輯來實作Ed Morton的評論(一旦FNR > 來自 注釋: uj5u.com熱心網友回復: 如果你有一個行號檔案,在每個行號的末尾添加 如果 那么 那么 我沒有發送足夠的行數來匹配15858,所以那一行沒有列印出來。
這與從檔案中解壓的效果相同。 這與從檔案中解壓的效果相同。
uj5u.com熱心網友回復: 為了澄清我之前的評論。我將展示一個簡單的可重復的樣本: 為了澄清我之前的評論。
為了模擬一個長的輸入,我將使用 將sed方案與我的建議相比較,我們有: 輸出: 將我的解決方案與awk進行比較: 輸出: 在我的結論中,使用 無論如何,這個測驗是簡單的,只對小范圍的比較有用。我不知道,例如,如果我對真正的壓縮檔案進行測驗,結果會是什么,因為有大量的磁盤 I/O。
awk 'FNR==NR {nums[$1];next} FNR in nums. FNR in nums' select.txt < (xz -dcq huge.txt.xz)
select.txt的最大值就退出處理):awk '
# 處理第一個檔案
FNR==NR { nums[1美元]
maxFNR= (1>maxFNR ? 1 : maxFNR)
下一個
}
# 處理隨后的檔案。
FNR > maxFNR { 退出 }
FNR in nums
' select.txt < (xz -dcq huge.txt.xz)
FNR > maxFNR顯然會在整個操作中增加一些cpu/處理時間(盡管比FNR in nums的時間要少)FNR > maxFNR可能會提供很少的好處(并且可能會減慢操作)FNR> maxFNR可能值得花費cpu/處理時間來避免掃描整個輸入流(然后,在整個檔案上的xz操作可能是最大的時間消耗)NFR > maxFNR測驗可能會加快/減慢整個程序,這取決于在一個典型的運行中需要處理多少輸入流;OP將需要運行一些測驗,看看整體運行時間是否有(明顯的)差異p,并作為一個sed腳本運行。linelist包含10
14
1499
15858
sed 's/$/p/' linelist > selector創建10p
14p
1499p
15858p
$: for n in {1. 1500}; do echo $n; done| sed -nf selector
10
14
1499
$: tar xOzf x.tgz | sed -nf selector
10
14
1499
linelistlinelist內容:10
15858
14
1499
seq -w 100000000。#!/bin/bash
時間 (
sed 's/$/p/' linelist > selector
seq -w 100000000 | sed -nf selector
)
時間 (
sort -n linelist | sed '$! {s/$/p/};$s/$/{p;q}/' > my_selector
seq -w 100000000 | sed -nf my_selector
)
0000010
000000014
000001499
000015858
真實 1m23.375s
用戶 1m38.004s
sys 0m1.337s
000000010
000000014
000001499
000015858
real 0m0.013s
用戶 0m0.014s
sys 0m0.002s
#!/bin/bash
時間 (
awk '
# 處理第一個檔案
FNR==NR { nums[1美元]
maxFNR= (1>maxFNR ? 1 : maxFNR)
下一個
}
# 處理隨后的檔案。
FNR > maxFNR { 退出 }
FNR in nums
' linelist <(seq -w 100000000)
)
時間 (
sort -n linelist | sed '$! {s/$/p/};$s/$/{p;q}/' > my_selector
sed -nf my_selector < (seq -w 100000000)
)
0000010
000000014
000001499
000015858
真實 0m0.023s
用戶 0m0.020s
sys 0m0.001s
000000010
000000014
000001499
000015858
real 0m0.017s
用戶 0m0.007s
sys 0m0.001s
q的seq與awk解決方案相當。對于可讀性和可維護性,我更喜歡awk解決方案。
Ed Morton 的編輯:
任何導致所有輸出值小于一秒的速度測驗都是一個糟糕的測驗,因為:
上述例子的問題在于,它只是試圖列印4行,而不是OP所說的必須選擇的1000行,所以它沒有行使sed和awk解決方案之間的差異,導致sed解決方案比awk解決方案慢得多,即sed解決方案必須為每一行輸入測驗每個目標行號,而awk解決方案只是對當前行進行一次哈希查詢。這是在輸入檔案的每一行上進行的 order(N) vs order(1) 的演算法。
這里有一個更好的例子,顯示了從一個1000000行的檔案中列印每100行(即將選擇1000行),而不是從任何大小的檔案中只列印4行:
。$ cat tst_awk.sh
#!/usr/bin/env bash
n=1000000
m=100
awk -v n="$n" -v m="$m 'BEGIN{for (i=1; i<=n; i =m) print i}' > linelist
seq "$n"|
awk '
FNR==NR {
nums[1美元]
maxFNR = 1美元
下一個
}
FNR在nums中 {
列印
if ( FNR == maxFNR ) {
退出
}
}
' linelist -
$ cat tst_sed.sh
#!/usr/bin/env bash
n=1000000
m=100
awk -v n="$n" -v m="$m 'BEGIN{for (i=1; i<=n; i =m) print i}' > linelist
sed '$!{s/$/p/};$s/$/{p;q}/' linelist > my_selector
seq "$n" !
sed -nf my_selector
$ time ./tst_awk.sh > ou.awk
real 0m0.376s
用戶 0m0.311s
sys 0m0.061s
$ time ./tst_sed.sh > ou.sed
真實 0m33.757s
用戶 0m33.576s
sys 0m0.045s
正如你所看到的,awk方案比sed方案快了2個數量級,而且它們產生了相同的輸出:
。
$ diff ou.awk ou.sed
$
如果我把輸入檔案變大,并通過設定從其中選擇10,000行:
n=10000000
m=1000
在每個腳本中,這可能是越來越現實的OPs使用,差異變得非常令人印象深刻:
在每個腳本中,這可能是越來越現實的OPs使用,差異變得非常令人印象深刻。
$ time ./tst_awk.sh > ou.awk
real 0m2.474s
用戶 0m2.843s
sys 0m0.122s
$ time ./tst_sed.sh > ou.sed
real 5m31.539s
用戶 5m31.669s
sys 0m0.183s
即awk在2.5秒內運行,而sed需要5.5分鐘!
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/318118.html
標籤:
