在 unix 中将大文件拆分为多个文件

use*_*167 4 linux awk split files

我有一个包含多行(9074 行)的文件,我想将该文件拆分为 10 个包含相同行数的文件,但最后一个文件包含剩余的行数

split -l `wc -l myfile | awk '{print $1/10}'` myfile
split: invalid number of lines: ‘907.4’
Run Code Online (Sandbox Code Playgroud)

我希望最后一个文件包含 907+4 行

tha*_*isp 9

您必须进行整数除法才能获得 的-l参数值split。shell 只适用于整数除法:

lines_number=$(wc -l < file)
split -l $((lines_number / 10)) file
wc -l x*
  907 xaa
  907 xab
  907 xac
  907 xad
  907 xae
  907 xaf
  907 xag
  907 xah
  907 xai
  907 xaj
    4 xak
 9074 total
Run Code Online (Sandbox Code Playgroud)

如果要为此使用awk,则必须打印一个整数:

wc -l file | awk '{print int($1/10)}'
907
Run Code Online (Sandbox Code Playgroud)

您必须连接最后两个文件。假设您将它们全部输出到同一个空目录中,您可以执行以下操作:

printf "%s\n" x* | tail -n2 | xargs cat > last_file

wc -l < last_file
911
Run Code Online (Sandbox Code Playgroud)

在上面,我们知道 glob 匹配将按字母顺序获取新文件,并且我们知道 split 正在按该顺序命名输出文件。


注意:此外,我更喜欢对 的输出文件使用自定义前缀和数字索引split,如下所示:

split -d -l 907 file new_file
Run Code Online (Sandbox Code Playgroud)

注意:由于后缀长度默认为 2,(参见man split-asplit会将文件命名为 ,只要它们小于 100(3 位后缀长度)new_file00new_file01它们将再次按字母顺序排序。具有数字后缀(为了人类可读性)和字母顺序的另一种选择是将后缀长度-a设置为适当的值。


要将整个过程包含在一个小脚本中,您可以这样做。我还添加了对模数是否为零的检查,在这种情况下,我们不修改任何输出文件。

#!/bin/bash
f="file"
prefix="new_file"

lines_number=$(wc -l < "$f")
split -d -l $((lines_number / 10)) "$f" "$prefix"

if ((lines_number % 10 != 0)); then
    last_file=$(printf "%s\n" "$prefix"* | tail -1)
    pre_last_file=$(printf "%s\n" "$prefix"* | tail -2 | head -1)
    cat "$last_file" >> "$pre_last_file" && rm -- "$last_file"
fi
Run Code Online (Sandbox Code Playgroud)