删除linux中的行

时间:2014-03-13 21:54:41

标签: python linux bash file-io

我有许多包含按日期记录的信息的大量分隔文本文件。有些文件按日期略有重叠(我不想要,因为它会导致重复)。我知道重叠日期是什么,所以我希望能够浏览一些文件并删除包含这些指定日期的每一行。

我知道如何在python中执行此操作(重写我想要的每一行),但由于文件的大小(每个是几GB),我想知道通过linux执行此操作是否会快得多?

文本文件将按日期排序,最早到最晚,我需要删除的日期总是位于文件的开头,所以我可以搜索,直到我遇到一个日期紧接着的日期我想要删除并将文件的其余部分写出到另一个文件(或删除上面的所有内容)。

4 个答案:

答案 0 :(得分:1)

因此,从文件的开头或中间删除数据非常昂贵。但是,将数据附加到文件或从文件末尾删除数据要便宜得多。

在这种情况下,我们假设我们有一个文件:

import io
fd = io.FileIO('foo.txt', 'r+')

让我们做一些工作来确定文件开始与bar.txt重叠的偏移量。

# You do some work...
offset = compute_overlap_offset()

现在,让我们截断foo.txt,以便不再重叠。

fd.truncate(offset)

答案 1 :(得分:0)

有各种命令行应用程序可以在一起工作时完成此任务。例如,您可以cat一个接一个地{(1}}所有文件,grep -v您不想要的模式,将>>重定向到新文件。实际上,这与Python脚本的作用相同,因为必须复制每个文件的每一行(重复项除外)。但它可能比Python更快,因为这些工具是用C语言编写的。

答案 2 :(得分:0)

您可以这样做以查看特定文件的最后几行:

$ tail file

从中获取最终日期,然后使用grep在与该日期匹配的行的另一个文件中查找行号:

$ grep -n 2012-10-23 nextfile
100234: 2012-10-23 etc whatever

现在将其后的行添加到新文件中:

$ tail -n +100235 nextfile >nextfile_truncated

请注意,我从grep输出中获取输出行号,并在最后一个尾操作中将其递增1,以获得匹配行之后的所有内容。

现在您可以比较文件的原始版本和截断版本(例如使用diff),并且一旦满意就删除原始版本。

答案 3 :(得分:0)

这就是我所能推断的情况:

  • 您有两个大型日志文件:file1.logfile2.log
  • 日志按时间顺序包含条目:file1.log位于file2.log
  • 之前
  • 许多条目显示在file1.log的末尾和file2.log
  • 的开头

如果这些日志文件具有高分辨率时间戳或具有不同的行(如Linux上的大多数日志文件),您所要做的就是找到第一次出现 last < / em> file1.log中的file2.log行:这会为您提供重复行块的大小,然后您可以从file1.log截断。

我希望这是使用通常的* nix实用程序(搜索开头,截断而不是尝试删除开头等)的最快方法。

以下在我的测试中有效,但不处理任何特殊情况(如file1。日志非常小等)。

#!/bin/bash

test_mode=false

file1="$1"
file2="$2"

# Last line of file1:
last=$(tail -1 "$file1")

# Use fgrep because we want an exact match and don't need regexes.
# Bug out after the first match (-m1), return the byte offset (-b),
# and extract this number from the match with cut:
nb=$(fgrep -bm1 "$last" "$file2" | cut -d: -f1)

# 'nb' now is the byte offset to the *start* of 'last' in file2; the
# *total* size of the repeated lines *includes* last itself:
ln=$(echo "$last"|wc -c)
nb=$(( $nb + $ln ))

# The size of file1 less the repeated lines is:
sz=$(( $(stat -c%s "$file1") - $nb ))

# Down to business!
if [ $test_mode == 'false' ]; then
    # Hack the end off file1:
    truncate -s $sz "$file1"
else
    echo "New size of '$file1' would be $sz bytes"
    dd if="$file1" bs=1 skip=$sz count=$ln
fi

Shell我用于合成示例(在复制19000-ish内核日志文件之后):

$ rm -f xa[a-z] && split -l 10000 kern.log && tail -n1 xaa && ls -l xaa && head -n100 xab >> xaa