如果我无法提取整个文件,是否可以拆分一个巨大的文本文件(基于行数)解压缩 .tar.gz 存档?

Is it possible to split a huge text file (based on number of lines) unpacking a .tar.gz archive if I cannot extract that file as whole?

我有一个 .tar.gz 文件。它包含 一个 20GB 大小的文本文件,包含 2050 万行。我无法将此文件作为一个整体提取并保存到磁盘。我必须执行以下任一选项:

  1. 在每个文件中指定行数 - 例如 100 万 - 并获得 21 个文件。这将是一个首选方案。
  2. 根据行号提取该文件的一部分,即从1000001到2000001,得到一个1M行的文件。我将不得不使用不同的参数重复此步骤 21 次,这非常糟糕。

有可能吗?

这个答案 - bash: extract only part of tar.gz archive - 描述了一个不同的问题。

你可以使用

sed -n 1,20p /Your/file/Path

这里你提到你的第一行号和最后一行号 我的意思是说这看起来像

sed -n 1,20p /Your/file/Path >> file1

并在变量中使用起始行号结束行号并使用它因此。

您可以使用 tar 中的 --to-stdout(或 -O)选项将输出发送到标准输出。 然后使用 sed 指定你想要的那一组行。

#!/bin/bash
l=1
inc=1000000
p=1
while test $l -lt 21000000; do
  e=$(($l+$inc))
  tar -xfz --to-stdout myfile.tar.gz file-to-extract.txt |
      sed -n -e "$l,$e p" > part$p.txt
  l=$(($l+$inc))
  p=$(($p+1))
done

要从 f.tar.gz 中提取文件并将其拆分为文件,每个文件不超过 100 万行,请使用:

tar Oxzf f.tar.gz | split -l1000000

以上将按默认方式命名输出文件。如果您希望将输出文件命名为 prefix.nn,其中 nn 是序列号,则使用:

tar Oxzf f.tar.gz |split -dl1000000 - prefix.

在这种方法下:

  • 原始文件永远不会写入磁盘。 tar.tar.gz 文件中读取并 将其内容通过管道 传输到 split 并将其分成多个部分,然后再将这些部分写入磁盘。

  • .tar.gz 文件只读一次。

  • split,通过其众多选项,具有很大的灵活性。

说明

对于tar命令:

  • O 告诉 tar 将输出发送到标准输出。这样我们就可以将它传输到 split 而无需将原始文件保存在磁盘上。

  • x 告诉 tar 提取文件(而不是创建存档)。

  • z 告诉 tar 存档是 gzip 格式。在现代 tars 上,这是可选的

  • f 告诉 tar 使用指定的文件名作为输入。

对于split命令:

  • -l 告诉 split 拆分受行数限制的文件(而不是字节数)。

  • -d 告诉 split 对输出文件使用数字后缀。

  • - 告诉 split 从 stdin

  • 获取输入

这是选项 #1 的纯 Bash 解决方案,自动将行拆分为多个输出文件。

#!/usr/bin/env bash

set -eu

filenum=1
chunksize=1000000
ii=0
while read line
do
  if [ $ii -ge $chunksize ]
  then
    ii=0
    filenum=$(($filenum + 1))
    > out/file.$filenum
  fi

  echo $line >> out/file.$filenum
  ii=$(($ii + 1))
done

这将从 stdin 中获取任何行并创建文件,例如 out/file.1 的前一百万行,out/file.2 的第二百万行,等等。然后你需要做的就是将输入提供给上面的脚本,像这样:

tar xfzO big.tar.gz | ./split.sh

这不会将任何中间文件保存在磁盘上,甚至不会保存在内存中。它完全是一个流媒体解决方案。这有点浪费时间,但在 space 方面非常有效。它也非常便携,应该可以在 Bash 以外的 shell 中工作,并且在几乎没有变化的古老系统上也能工作。