在没有预先定义的块长度的情况下,在两个文件之间按行拆分文件 - Unix

时间:2016-04-26 02:31:23

标签: bash split text-files line

我有两个长度相等的文件(即行号):

  • text.en
  • text.cs

我想逐步将文件分成12个部分,当我迭代时,我需要在前10个部分中添加1个。

让我们说如果我的文件包含100行,我需要某种循环:

#!/bin/bash

F1=text.en
F2=text.cs

for i in `seq 0 9`;
do
    split -n l/12 -d text.en
    cat x10 > dev.en
    cat x11 > test.en
    echo "" > train.en
    for j in `seq 0 $i`; do
        cat x0$j >> train.en
    done

    split -n l/12 -d text.cs
    cat x10 > dev.cs
    cat x11 > test.cs
    echo "" > train.cs
    for j in `seq 0 $i`; do
        cat x0$j >> train.cs
    done

    wc -l train.en train.cs
    echo "############"
done

[OUT]:

   55632 train.en
   55468 train.cs
  111100 total
############
  110703 train.en
  110632 train.cs
  221335 total
############
  165795 train.en
  165011 train.cs
  330806 total
############

它给了我文件之间不相等的块。

此外,当我使用split时,它会分成不相等的块:

alvas@ubi:~/workspace/cvmt$ split -n l/12 -d text.en
alvas@ubi:~/workspace/cvmt$ wc -l x*
   55631 x00
   55071 x01
   55092 x02
   54350 x03
   54570 x04
   54114 x05
   55061 x06
   53432 x07
   52685 x08
   52443 x09
   52074 x10
   52082 x11
  646605 total

我不知道没有。我手边的文件行,所以我不能使用split -l选项。

如何将文件拆分为相等的大小。考虑到我之前不知道文件中有多少行?我应该使用wc -l进行某种预先计算吗?

如何确保每个块中两个文件的分割大小相同?

(请注意,解决方案需要在行尾分割文件,即不要拆分任何行,只需逐行拆分文件。)

1 个答案:

答案 0 :(得分:4)

您并不完全清楚自己想要实现的目标,但这里有几点建议:

split -n l/12分成12个大小相等字节大小的块,而不是行数

split -n r/12尝试均匀地分发行数,但如果块大小不是总行数的除数,那么你可以' ll仍会得到(稍微)不同的行数:额外行以循环方式分布

例如,如果有100个输入行且行块大小为12,那么您的行数将为9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8100 / 12 = 8(整数除法)和100 % 12 = 4,所以所有文件至少 8,在前4个输出文件中分配额外的4行。

所以,是的,如果你想要所有文件的固定行数(除了最后一个,如果块大小不是除数),你必须预先计算总行数,执行整数除法以获得固定的行数,并使用split -l计数:

 totalLines=$(wc -l < text.en)
 linesPerFile=$(( totalLines / 12 ))

 split -l 12 text.en # with 100 lines, yields 8 files with 12 and 1 with 4 lines

补充意见:

使用小的固定迭代计数,使用大括号扩展(例如,for i in {0..9}而非for i in `seq 0 9`)更容易,更有效。

如果必须使用变量或使用更大的数字,请使用算术表达式: n=9; for (( i = 0; i <= $n; i++ )); do ...; done

虽然您无法直接执行cat x0{0..$i}(因为Bash在大括号扩展中不支持变量),但您可以通过合并seq -fxargs来模拟它:

您可以替换

echo "" > train.en
for j in `seq 0 $i`; do
    cat x0$j >> train.en
done

以下内容:

seq -f 'x%02.f' "$i" | xargs cat > train.en

由于您控制$i的值,您甚至可以简化为:

eval "cat x0{0..$i}" > train.en  # !! Only do this if you trust $i to contain a number.