根据内容在linux中拆分文件[重复]
Posted
技术标签:
【中文标题】根据内容在linux中拆分文件[重复]【英文标题】:Splitting a file in linux based on content [duplicate] 【发布时间】:2022-01-08 18:37:02 【问题描述】:我有一个大约 400mb 的电子邮件转储。我想将其拆分为 .txt 文件,每个文件中包含一封邮件。每封电子邮件都以指定文档类型的标准 html 标头开头。
这意味着我将不得不根据上述标题拆分我的文件。在 linux 中如何处理?
【问题讨论】:
这真的是电子邮件转储吗?你的意思是你根本没有邮件标题?你怎么称呼“指定文档类型的标准 HTML 标头”? ""-//W3C//DTD HTML 4.01 Transitional//EN\">如果你有mail.txt
$ cat mail.txt
<html>
mail A
</html>
<html>
mail B
</html>
<html>
mail C
</html>
运行csplit
以<html>
分割
$ csplit mail.txt '/^<html>$/' '*'
- mail.txt => input file
- /^<html>$/ => pattern match every `<html>` line
- * => repeat the previous pattern as many times as possible
检查输出
$ ls
mail.txt xx00 xx01 xx02 xx03
如果你想在awk
做它
$ awk '/<html>/filename=NR".txt"; print >filename' mail.txt
$ ls
1.txt 5.txt 9.txt mail.txt
【讨论】:
我害怕!我做了同样的事情并做了一个 $ls mail.txt xx00 并且显然 mail.txt 与 xx00 相同。任何修复? @Ramprakash 我的csplit
的版本是8.5
。也许你的没有重复模式的*
。请检查手册页。我只是添加awk
解决方案。你可以试试看。
@Greenhorn 我的csplit
版本也不支持*
,但这有效:csplit -n 6 -f 'mail-' -k mail.txt '/^<html>$/' '5000'
为了防止在第一行与模式不匹配时出现awk
错误(至少对于gawk
),请执行以下操作:awk 'BEGIN filename="0.txt" /...'
【参考方案2】:
csplit
程序优雅地解决了您的问题:
csplit '/<!DOCTYPE.*/' $FILE
【讨论】:
参数的顺序错误,并且没有按预期进行重复。【参考方案3】:csplit
是解决这个问题的最佳方案。只是想我会发布一个 bash 解决方案来表明没有必要在这个任务上使用 perl:
#!/usr/bin/bash
MAIL='mail' # path to huge mail-file
#get linenumbers for all headers
line_no=$(grep -n html $MAIL | cut -d: -f1)
read -a LINES<<< $line_no
file=0
for i in $(seq 0 2 $#LINES[@]); do
start=$LINES[i]
end=$(($LINES[i+1]-1))
echo $start, $end
sed -n "$start,$endp" $MAIL > $MAIL$file.txt
file=$((file+1))
done
【讨论】:
【参考方案4】:我同意 fge。使用perl
会简单得多。你可以试试这样的 -
#!/usr/bin/perl
undef $/;
$_ = <>;
$n = 0;
for $match (split(/(?=HEADER_FORMAT)/))
open(O, '>mail' . ++$n);
print O $match;
close(O);
将HEADER_FORMAT
替换为您的标头类型。
【讨论】:
是的,积极的前瞻会很好地工作,特别是因为这里的标题不包含任何元字符。您甚至可以使用qr//
来构建拆分正则表达式。【参考方案5】:
使用一些 perl 的“魔法”是可行的...很多人会说这很丑,但这里就是这样。
诀窍是将$/
替换为您想要的内容并读取您的输入,如下所示:
#!/usr/bin/perl -W
use strict;
my $i = 1;
$/ = <<EOF;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <xmeta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
EOF
open INPUT, "/path/to/inputfile" or die;
while (my $mail = <INPUT>)
$mail = substr($mail, 0, index($mail, $/));
open OUTPUT, ">/path/to/emailfile." . $i . ".txt" or die;
$i++;
print OUTPUT $mail;
close OUTPUT;
编辑:已修复,我总是忘记 $/
包含在输入中。此外,第一个文件将始终为空,但随后可以轻松处理。
【讨论】:
以上是关于根据内容在linux中拆分文件[重复]的主要内容,如果未能解决你的问题,请参考以下文章