如果我无法提取整个文件,是否可以拆分一个巨大的文本文件(基于行数)解压缩 .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 万行。我无法将此文件作为一个整体提取并保存到磁盘。我必须执行以下任一选项:
- 在每个文件中指定行数 - 例如 100 万 - 并获得 21 个文件。这将是一个首选方案。
- 根据行号提取该文件的一部分,即从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 中工作,并且在几乎没有变化的古老系统上也能工作。
我有一个 .tar.gz 文件。它包含 一个 20GB 大小的文本文件,包含 2050 万行。我无法将此文件作为一个整体提取并保存到磁盘。我必须执行以下任一选项:
- 在每个文件中指定行数 - 例如 100 万 - 并获得 21 个文件。这将是一个首选方案。
- 根据行号提取该文件的一部分,即从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 中工作,并且在几乎没有变化的古老系统上也能工作。