根据内容在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\"> 这后面是整个电子邮件! 【参考方案1】:

如果你有mail.txt

$ cat mail.txt
<html>
    mail A
</html>

<html>
    mail B
</html>

<html>
    mail C
</html>

运行csplit&lt;html&gt;分割

$ 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 '/^&lt;html&gt;$/' '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中拆分文件[重复]的主要内容,如果未能解决你的问题,请参考以下文章

根据输入偏移值拆分数组,但在同一块中保留重复

根据字符串的不同模式拆分字符串[重复]

linux shell脚本:拆分字符串,将它们放在一个数组中然后循环它们[重复]

用于根据空格分隔符拆分文本的正则表达式 [重复]

在拆分为多个文件的大型数据框中查找重复行和包含重复行的文件

根据值的数量将熊猫列拆分为多个单独的列[重复]