如何更有效地將文件切成碎片?

如何更有效地將文件切成碎片?

假設我有一個 10MB 的文字文件foo.txt,它有 100,000 行。現在,我想foo.txt逐個視窗處理,視窗大小為 10。

我目前的腳本是這樣的:

for ((i=0;i<$lines;i=i+$step))
do    
    head -$((i+step)) $1 | tail -$step > tmp1
    head -$((i+step)) $2 | tail -$step > tmp2
    setstr=$setstr' '`./accuracy.sh tmp1 tmp2`
done
echo $setstr | awk '{for (i=1;i<=NF;i++) sum+=$i; }END{print sum/NF}'

但它運行緩慢。有沒有簡單且更有效的方法來做到這一點?

答案1

你可以這樣做split

以下是如何使用它的範例:

split -l 10 input_file output_file_prefix_

-l選項代表--lines=

這將分成input_file每塊 10 行的區塊,放入以下文件中:

output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...

等等。

您可以使用的其他方式split,請參閱man split這裡

答案2

擁有更多關於您的最終目標的背景資訊而不是程式碼片段會很有用。特別是,你對accuracy.sh有任何控制嗎?

無論如何,如果你想繼續使用 bash,那麼你可以這樣做

for ((i=0;i<$lines;i+=$step))
do
  let end=i+10
  sed -n $i,${end}p $1 >tmp1
  sed -n $i,${end}p $2 >tmp2
  ...
done

答案3

不知道為什麼這是從 StackOverflow 遷移的。雖然split是一個超級用戶-風格的答案,問題是關於程式設計的。例如,這是一個實現您在 中尋找的內容的答案awk

真正方便的方面之一awk是它處理管道的方式。

#!/usr/bin/awk -f

BEGIN {
  cmd="/path/to/handler"
}

{
  print | cmd
}

NR % 10 == 0 {
  close(cmd)
}

如果它已關閉,您cmd將重新開啟...並且每 10 行關閉一次,然後在下一行輸出中重新開啟。

效果是handler每 10 行輸入運行一次。在文件末尾,handler將使用剩餘的任何行運行,因為cmdawk 退出時會自動關閉。

嚴格來說,您不需要使用像cmd存儲命令這樣的變數......但它確實使調整命令變得更簡單,因為否則您需要非常仔細地觀察close().

答案4

此解決方案不使用任何臨時檔案。它的作用是將每一行儲存在一個可以容納十行的緩衝區陣列中。每次行號可以被十整除時,它都會列印緩衝區中的所有行。

明顯的陷阱是當輸入檔(# 行)不能被 10 整除。解決方案是在 END{} 子句中進行檢查。就像是:

$ 回顯 {1..33} | tr \ \\n |\
    awk '{lines=NR} END{ if (lines%10!=0) { print "剩餘行"} }'
剩餘線

# STEP1 使用模每十分之一做某事
$ echo {1..200} |tr \ \\n |\
    awk '{a[NR%10]=$0; if (NR%10==0) {print "10"} }' |貓-n
     1 十
     2 十
     3 十
     4 十
     5 十
     6 十
     7 十
     8 十
     9 十
    10 十
    11 十
    12 十
    13 十
    14 十
    15 十
    16 十
    17 十
    18 十
    19 十
    20 十

# 第 2 步對每一行做一些事情
$ 回顯 {1..10} | tr \ \\n | awk '{ b+=$0} END {print b}'
55

# 把它放在一起
$ 貓 every10.awk
{
        [NR%10]=$0;
        如果(NR%10==0){
                對於(a中的i){
                        printf "%s+", a[i]
                        b+=a[i];
                }
                列印“0=”b;
                b=0
        }
}
$ 回顯 {1..200} | tr \ \\n | awk -f every10.awk | awk -f every10.awk | awk -f every10.awk |列-s=-t
4+5+6+7+8+9+10+1+2+3+0 55
14+15+16+17+18+19+20+11+12+13+0 155
24+25+26+27+28+29+30+21+22+23+0 255
34+35+36+37+38+39+40+31+32+33+0 355
44+45+46+47+48+49+50+41+42+43+0 455
54+55+56+57+58+59+60+51+52+53+0 555
64+65+66+67+68+69+70+61+62+63+0 655
74+75+76+77+78+79+80+71+72+73+0 755
84+85+86+87+88+89+90+81+82+83+0 855
94+95+96+97+98+99+100+91+92+93+0 955
104+105+106+107+108+109+110+101+102+103+0 1055
114+115+116+117+118+119+120+111+112+113+0 1155
124+125+126+127+128+129+130+121+122+123+0 1255
134+135+136+137+138+139+140+131+132+133+0 1355
144+145+146+147+148+149+150+141+142+143+0 1455
154+155+156+157+158+159+160+151+152+153+0 1555
164+165+166+167+168+169+170+161+162+163+0 1655
174+175+176+177+178+179+180+171+172+173+0 1755
184+185+186+187+188+189+190+181+182+183+0 1855
194+195+196+197+198+199+200+191+192+193+0 1955

這裡的想法是使用 awk 列印十行區塊並處理它,或者如果操作是簡單的算術或字串運算,則直接使用 awk 處理。

相關內容