【问题标题】:Splitting files by line across two files equally without pre-defined chunk length - Unix在没有预定义块长度的情况下,在两个文件中按行平均分割文件 - Unix
【发布时间】:2016-04-26 02:31:23
【问题描述】:

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

  • text.zh
  • 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

[出]:

   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 进行某种预计算吗?

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

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

【问题讨论】:

    标签: bash split text-files line


    【解决方案1】:

    目前尚不完全清楚您要达到的目标,但这里有几点建议:

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

    split -n r/12尝试平均分配 行数,但如果块大小不是总行数的除数,您仍然会得到 (稍微)不同的行数:额外的行以循环方式分布

    例如,对于 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 &lt;= $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.
    

    【讨论】:

    • 酷!我从来没有想过管道seq | xargs =)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2021-08-10
    • 2010-10-28
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    相关资源
    最近更新 更多