在没有预定义的块长度的情况下,将文件按行平均分割为两个文件-Unix

alv*_*vas 1 bash split line text-files

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

  • text.en
  • text.cs

我想将文件逐步拆分为12个部分,并在进行迭代时,需要在前十个部分中添加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
Run Code Online (Sandbox Code Playgroud)

[出]:

   55632 train.en
   55468 train.cs
  111100 total
############
  110703 train.en
  110632 train.cs
  221335 total
############
  165795 train.en
  165011 train.cs
  330806 total
############
Run Code Online (Sandbox Code Playgroud)

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

另外,当我使用时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
Run Code Online (Sandbox Code Playgroud)

我不知道没有。文件的行数,因此我无法使用该split -l选项。

我如何将文件分割成相等大小。假设我不知道文件中预先存在多少行,那是多少行?我应该用某种方式进行预计算wc -l吗?

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

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

mkl*_*nt0 5

尚不清楚您要实现的目标,但是这里有一些提示:

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

split -n r/12尝试平均分配行数,但是如果块大小不是总行数的除数,您仍然会(略有)不同的行数:多余的行采用循环方式分配

例如,如果输入行数为100,行块大小为12,则行数为9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8:(100 / 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
Run Code Online (Sandbox Code Playgroud)

其他观察:

固定的迭代次数较少,因此使用括号扩展(例如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 -f和来模拟它xargs

您可以更换

echo "" > train.en
for j in `seq 0 $i`; do
    cat x0$j >> train.en
done
Run Code Online (Sandbox Code Playgroud)

具有以下内容:

seq -f 'x%02.f' "$i" | xargs cat > train.en
Run Code Online (Sandbox Code Playgroud)

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

eval "cat x0{0..$i}" > train.en  # !! Only do this if you trust $i to contain a number.
Run Code Online (Sandbox Code Playgroud)