sed / awk / perl删除3线模式的前两行

时间:2019-09-24 19:52:37

标签: perl ubuntu awk sed

我有一个巨大的文本文件。我需要替换所有出现的这三行 模式:

|pattern|some data|
|giberish|,,
|pattern|some other data|

在模式的最后一行:

|pattern|some other data|

删除模式的前两行,仅保留最后一行

  • 模式的第二行以两个逗号结尾,而不以|pattern|开头
  • 图案行的第一行以|pattern|开头,并且不以两个逗号结尾。
  • 模式行的第三行以|pattern|开头,并且不以两个逗号结尾。

我尝试过:

sed 'N;N;/^|pattern|.*\n.*,,\n|pattern|.*/I,+1 d' trial.txt

运气不好

编辑:这是一个更重要的示例

#!/usr/bin/env bash
cat > trial.txt <<EOL
|pattern|sdkssd|
|.x,mz|e,dsa|,,
|pattern|sdk;sd|
|xl'x|cxm;s|,,
|pattern|aslkaa|
|l'kk|3lke|,,
|x;;lkaa|c,c,s|
|-0-ses|3dsd|
|xk;xzz|'l3ld|
|0=9c09s|klkl32|
|d0-zox|m,3,a|
|x'.za|wkl;3|
|=-0poxz|3kls|
|x-]0';a|sd;ks|
|wsd|756|
|sdw|;lksd|
|pattern|askjkas|
|xp]o]xa|lk3j2|,,
|]-p[z|lks|
EOL

它应该变成:

|pattern|aslkaa|
|l'kk|3lke|,,
|x;;lkaa|c,c,s|
|-0-ses|3dsd|
|xk;xzz|'l3ld|
|0=9c09s|klkl32|
|d0-zox|m,3,a|
|x'.za|wkl;3|
|=-0poxz|3kls|
|x-]0';a|sd;ks|
|wsd|756|
|sdw|;lksd|
|pattern|askjkas|
|xp]o]xa|lk3j2|,,
|]-p[z|lks|

@zdim:

文件的前三行:

|pattern|sdkssd|
|.x,mz|e,dsa|,,
|pattern|sdk;sd|

满足模式。因此将它们替换为

|pattern|sdk;sd|

因此文件的顶部现在变为:

|pattern|sdk;sd|
|xl'x|cxm;s|,,
|pattern|aslkaa|
|l'kk|3lke|,,
...

其中的前三行是:

|pattern|sdk;sd|
|xl'x|cxm;s|,,
|pattern|aslkaa|

满足该模式,因此将其替换为:

|pattern|aslkaa|

所以文件的顶部现在是:

|pattern|aslkaa|
|l'kk|3lke|,,
|x;;lkaa|c,c,s|
|-0-ses|3dsd|
....

@JosephQuinsey:

考虑此文件:

#!/usr/bin/env bash
cat > trial.txt <<EOL
|pattern|blabla|
|||4|||-0.97|0|1429037262.8271||20160229||1025||1000.0|0.01|,,
|pattern|blable|
|||5|||-1.27|0|1429037262.854||20160229||1025||1000.0|0.01|,,
|pattern|blasbla|
|||493|||-0.22|5|1429037262.8676||20170228||1025||1000.0|0.01|,,
|||11|||-0.22|5|1429037262.8676||20170228||1025||1000.0|0.01|,|T|347||1429043438.1962|-0.22|5|0||-0.22|1429043438.1962|,|Q|346||1429043437.713|-0.24|26|-0.22|5|||1429043437.713|
|pattern|jksds|
|||232|||-5.66|0|1429037262.817||20150415||1025||1000.0|0.01|,,
|pattern|bdjkds|
|||123q|||-7.15|0|1429037262.8271||20150415||1025||1000.0|0.01|,,
|pattern|blabla|
|||239ps|||-1.38|79086|1429037262.8773||20150415||1025||1000.0|0.01|,,
|||-92opa|||-1.38|79086|1429037262.8773||20150415||1025||1000.0|0.01|,|T|1||1428969600.5019|-0.99|1|11||||,
|||kj2w|||-1.38|79086|1429037262.8773||20150415||1025||1000.0|0.01|,|T|2||1428969600.5019|-1|1|11||||,
|||0293|||-1.38|79086|1429037262.8773||20150415||1025||1000.0|0.01|,|T|3||1428969600.5019|-1.01|1|11||||,
|||2;;w32|||-1.38|79086|1429037262.8773||20150415||1025||1000.0|0.01|,|T|4||1428969600.5019|-1.11|1|11||||,
EOL

5 个答案:

答案 0 :(得分:5)

这很简单,使用缓冲区来收集和管理图案线

MyList

这将打印预期的输出。

说明。

  • 模式行放在缓冲区中,当我们获得“第三行”时,需要删除前两个行。然后,每当我们看到use warnings; use strict; use feature 'say'; my $file = shift or die "Usage: $0 file\n"; open my $fh, '<', $file or die "Can't open $file: $!"; my @buf; while (<$fh>) { chomp; if (/^\|pattern\|/ and not /,,$/) { @buf = $_; # start the buffer (first line) or overwrite (third) } elsif (/,,$/ and not /^\|pattern\|/) { if (@buf) { push @buf, $_ } # add to buffer with first line in it else { say } # not part of 3-line-pattern; print } else { say for @buf; # time to print out buffer @buf = (); # ... empty it ... say # and print the current line } } 时,就将它们“分配”给数组–如果缓冲区是第一行,则启动缓冲区;如果数组第三行,则重新初始化数组(删除数组中的内容)

    < / li>
  • ^|pattern|结尾的行已添加到缓冲区(如果已经有一行)。没有什么可以禁止以,,结尾的行-它们可能在模式之外;在这种情况下,只需打印

  • 因此,每条,,行都将缓冲区设置为笔直-启动或重置缓冲区。因此,一旦碰到既没有|pattern|也没有^|pattern|的行,我们就可以打印出缓冲区,并且该行

请更全面地测试,我仍然没有做。


要在管道或文件中运行此命令,请使用"magical" <>文件句柄。变成了

,,$

现在,您可以以use warnings; use strict; use feature 'say'; my @buf; while (<>) { # reads lines from files given on command line, or from STDIN ... } data | script.pl的身份运行它。 (为此使脚本可执行,或用作script.pl datafile。)

脚本的输出将转到perl script.pl,该脚本可以通过管道传输到其他程序或重定向到文件。

答案 1 :(得分:1)

更新后的答案: :以下 sed 解决方案应该可以工作:

  sed '/\n/!N;/\n.*\n/!N;/^|pattern|.*\n.*,,\n|pattern|/!{P;D;};s/[^\n]*\n//;D;'

说明:

  • /\n/!N如果P空间只有一行,请阅读下一行
  • /\n.*\n/!N,如果P空间只有两行,请读第三行
  • /^|pattern|.*\n.*,,\n|pattern|/测试第一行和第三行是否以| pattern |开头,中间行以两个逗号结尾
  • !{P;D;}如果匹配失败 ,则打印第一行并重新开始
  • s/[^\n]*\n//;D;否则,如果匹配成功 ,请删除前两行,然后重新开始。

答案 2 :(得分:1)

这可能取决于文件的大小,但如果文件大小小于允许的内存大小,怎么办:

|pattern|aslkaa|
|l'kk|3lke|,,
|x;;lkaa|c,c,s|
|-0-ses|3dsd|
|xk;xzz|'l3ld|
|0=9c09s|klkl32|
|d0-zox|m,3,a|
|x'.za|wkl;3|
|=-0poxz|3kls|
|x-]0';a|sd;ks|
|wsd|756|
|sdw|;lksd|
|pattern|askjkas|
|xp]o]xa|lk3j2|,,
|]-p[z|lks|

输出:

string tableName = _awsSettings.TableSettings.Table + _awsSettings.TableSettings.Suffix;
Table table = Table.LoadTable(_amazonDynamoDb, tableName);

DocumentBatchGet batch = table.CreateBatchGet();
await batch.ExecuteAsync();
List<Document> results = batch.Results;
return results.As<Lab>();

答案 3 :(得分:1)

awk解决方案:

awk -v pa=pattern '
    $0 ~ pa {
        do {
            hold=$0;
            getline;
            hold=hold "\n" $0;
            getline;
        } while(match($0, pa));
        print hold
    }
    1' trial.txt

想法是缓冲与模式匹配的行,然后缓冲之后的行。如果下一行也与模式匹配,则循环,这一次将缓冲最近的匹配行及其后一行。这样具有删除需要替换的行的作用。

当循环停止时,缓冲区包含的第一行要么是替换已删除行的行,要么就是不被删除的第一模式匹配。无论哪种方式,缓冲区的内容都会被打印出来。

需要最后的1语句来打印结束while循环的行以及所有其他与模式匹配后的第一或第二行的行。

答案 4 :(得分:1)

这可能对您有用(GNU sed):

sed ':a;N;s/[^\n]*/&/3;Ta;/^|pattern|.*\n.*,,\n|pattern|/{/,,\n.*\n\|,,$/!{s/.*\n//;ba}};P;D' file

用文件的后三行填充模式空间。如果第一模式与当前三行匹配,而第一行或第三行均未以,,结尾,则删除前两行并重复。否则,打印并删除三行窗口的第一行并重复。