如何通过计算行内的位数来分割文件?

如何通过计算行内的位数来分割文件?

我有一个每行包含 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

请问有什么建议吗?

答案1

您可以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

答案2

您可以通过使用读取和参数替换/扩展/分割来使用 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)。然后比较分裂,awk,其中awk实现是相同的史蒂芬·查泽拉斯版本。 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

比较如下:最佳性能,,被赋值为 1:

                             RELATIVE PERFORMANCE 

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

毫无疑问,在这种情况下,是用于较大文件的工具。来自 Bash 的粗略初步测试分裂上面,从文件读取时循环占用了大约 5 秒的 CPU 时间,参数扩展约占8秒,其余部分可以说与printf 到文件运营。

相关内容