Linux

如何通過計算一行中的數字來拆分文件?

  • October 9, 2015

我有一個每行有 45000 個字元的文件,我想根據一行中的特定字元數分割原始文件。作為一個小例子,我的輸入文件如下所示:

輸入.txt:

123394531112334455938383726644600000111234499922281133
234442221117273747474747474729292921111098887777772235
231112233647474838389292121037549284753930837475111013

每行有 54 位數字。我希望前 10 位數字是一個單獨的文件,而 11-24 是另一個文件。並從 25-32 位另一個文件和 33-50 的最後一個文件,如:

out1.txt (1-10)

1233945311
2344422211
2311122336

out2.txt (11-24)

12334455938383
17273747474747
47474838389292

out3.txt (25-32)

72664460
47472929
12103754

out4.txt (33-54)

0000111234499922281133
2921111098887777772235
9284753930837475111013

請問有什麼建議嗎?

您可以通過使用讀取和參數替換/擴展/拆分來使用 Bash 執行此操作。形式為 ${PARAMETER:OFFSET:LENGTH},其中 OFFSET 從零開始。例如,將以下文件另存為“split”,然後通過以下方式讀取每一行:

#!/usr/bin/env bash

# Usage: ./split "data.txt"

while IFS= read -r line
do
   printf '%s\n' "${line:0:10}"  >&3  #  1-10
   printf '%s\n' "${line:10:14}" >&4  # 11-24
   printf '%s\n' "${line:24:8}"  >&5  # 25-32
   printf '%s\n' "${line:32:22}" >&6  # 33-54
done < "$1" 3> output01.txt 4> output02.txt 5> output03.txt 6> output04.txt

# end file

當然你可能需要稍微調整上面的位置,但是你可以使用這個模型來處理很多不同類型的文件。 上述位置將產生所需的輸出。可以在bash-hackers.org找到一個很好的參考資料(關於參數擴展)


作為附言,在合併推薦的實踐改進(見評論)後,請記住,對於大文件,Bash 方法在 cpu 時間和 cpu 資源方面效率不高。為了量化這個陳述,我在下面準備了一個簡短的比較。首先創建一個長度為 300,000 行(16500000 字節)的開篇數據的測試文件(bigsplit.txt)。然後比較splitcutawk,其中cutawk實現與StéphaneChazelas版本相同。CPU 時間(以秒為單位)是系統和使用者 CPU 時間的總和,RAM 是最大使用時間。

$ stat -c %s bigsplit.txt && wc -l bigsplit.txt 
16500000
300000 bigsplit.txt

$ ./benchmark ./split bigsplit.txt 

CPU TIME AND RESOURCE USAGE OF './split bigsplit.txt'
VALUES ARE THE AVERAGE OF ( 10 ) TRIALS

CPU, sec :   88.41
CPU, pct :   99.00
RAM, kb  : 1494.40

$ ./benchmark ./cut bigsplit.txt 

CPU TIME AND RESOURCE USAGE OF './cut bigsplit.txt'
VALUES ARE THE AVERAGE OF ( 10 ) TRIALS

CPU, sec :    0.86
CPU, pct :   99.00
RAM, kb  :  683.60

$ ./benchmark ./awk bigsplit.txt

CPU TIME AND RESOURCE USAGE OF './awk bigsplit.txt'
VALUES ARE THE AVERAGE OF ( 10 ) TRIALS

CPU, sec :    1.19
CPU, pct :   99.00
RAM, kb  : 1215.60

比較如下,其中最佳性能cut被賦值為 1:

                            RELATIVE PERFORMANCE 

                                   CPU Secs     RAM kb
                                   --------     ------
                   cut                    1          1
                   awk                  1.4        1.8
                   split (Bash)       102.8        2.2

毫無疑問,在這種情況下,cut是用於較大文件的工具。從上面對 Bash split的粗略初步測試來看,while read from file循環大約佔 CPU 時間 5 秒,參數擴展大約 8 秒,其餘的可以說與printf 到文件操作有關。

您可以cut多次呼叫:

cut -c 1-10  < file > out1.txt
cut -c 11-24 < file > out2.txt
cut -c 25-32 < file > out3.txt
cut -c 33-54 < file > out4.txt

(請注意,儘管目前版本的 GNUcut不支持多字節字元(這不應該是您輸入中的 ASCII 十進制數字的問題))

或者awk一口氣:

awk '{
 print substr($0, 1,  10) > "out1.txt"
 print substr($0, 11, 14) > "out2.txt"
 print substr($0, 25, 8 ) > "out3.txt"
 print substr($0, 33, 22) > "out4.txt"}' < file

(請注意,awk目前版本的某些實現mawk不支持多字節字元(這不應該是 ASCII 十進制數字的問題))

使用 GNU awk,您還可以:

awk -v FIELDWIDTHS='10 14 8 22' '
 {for (i = 1; i <= NF; i++) print $i > "out" i ".txt"}' < file

引用自:https://unix.stackexchange.com/questions/234027