管awk的结果是sed(删除)

时间:2014-06-18 18:38:05

标签: regex bash awk sed

我正在使用打印这些行的awk命令(someawkcommand)(awkoutput):

>Genome1
ATGCAAAAG
CAATAA

然后,我想使用此输出(awkoutput)作为sed命令的输入。这样的事情:

someawkcommand | sed 's/awkoutput//g' file1.txt > results.txt

file1.txt:

>Genome1
ATGCAAAAG
CAATAA
>Genome2
ATGAAAAA
AAAAAAAA
CAA
>Genome3
ACCC

最终目标是删除包含awk先前找到的确切模式的文件(file1.txt)中的所有行。

文件results.txt包含(sed的输出):

>Genome2
ATGAAAAA
AAAAAAAA
CAA
>Genome3
ACCC

我该如何编写sed命令?是否有任何简单的方法可以将awk的输出识别为输入?

4 个答案:

答案 0 :(得分:1)

将GNU awk用于多字符RS:

$ cat file1
>Genome1
ATGCAAAAG
CAATAA

$ cat file2
>Genome1
ATGCAAAAG
CAATAA
>Genome2
ATGAAAAA
AAAAAAAA
CAA
>Genome3
ACCC

$ gawk -v RS='^$' -v ORS= 'NR==FNR{rmv=$0;next} {sub(rmv,"")} 1' file1 file2
>Genome2
ATGAAAAA
AAAAAAAA
CAA
>Genome3
ACCC

对于新手来说可能不明显的东西,但是非常常见的awk习语:

  1. -v RS='^$'告诉awk将整个文件读作一个字符串(而不是一次默认的一行)。
  2. -v ORS=将输出记录分隔符设置为空字符串(而不是它的默认换行符),这样当文件作为字符串打印时,awk不会在其后添加换行符。
  3. NR==FNR是仅对第一个输入文件为真的条件。
  4. 1是一个调用打印当前记录的默认操作的真实条件。

答案 1 :(得分:0)

这是一个可能的sed解决方案:

someawkcommand | sed -n 's_.*_/&/d;_;H;${x;s_\n__g p}' | sed -f - file1.txt

第一个sed命令将someawkcommand的输出转换为sed表达式。

具体而言,它会变成

>Genome1
ATGCAAAAG
CAATAA

成:

/>Genome1/d;/ATGCAAAAG/d;/CAATAA/d;

(使用sed语言:删除包含这些模式的行;请注意您必须转义/[]*,{ {1}},^输出中的$,如果有的话,还有其他替代例。)

第二个awk命令将其作为输入表达式读取(sed从文件-f -读取sed个命令,即从管道获取命令)并应用于文件{{1} }。

其他读者备注:
OP希望使用-,但正如评论中所述,它可能不是解决此问题的最简单方法。删除file1.txt行可能更简单。另一个(简单)解决方案可能是使用sedawk(反向匹配)和grep(从文件中读取模式)选项,这样:

-v

编辑:关注@ rici的评论,这是一个新命令,它将-f的输出作为单个多线模式。

免责声明:它变脏了。孩子们,不要回家。强烈建议成年人考虑避免someawkcommand | grep -v -f - file1.txt

awk

内部sed的输出是:

someawkcommand | \
    sed -n 'H;${x;s_\n__;s_\n_\\n_g;s_.*_H;${x;s/\\n//;s/&//g p}_ p}' | \
    sed -n -f - file1.txt

附加缺点:它会添加一个空行而不是删除模式。无法轻松修复(如果模式位于文件的开头/结尾,则会出现问题)。如果您真的愿意,请添加替换以将其删除。

答案 2 :(得分:0)

这可以更容易地在awk中完成,但通常"消除重复"代码不正确。据我所知,目标是从文件中删除整个节。

这是一个可能的解决方案,假设第一个awk脚本输出单个节:

awk 'NR == FNR       {stanza[nstanza++] = $0; next}
     $0 == stanza[i] {++i; next}
     /^>/ && i == nstanza {i=0; next}
     i               {for (j=0; j<i; ++j) print stanza[j]; i=0}
                     {print $0;}
    ' <(someawkcommand) file1.txt

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed '1{h;s/.*/:a;$!{N;ba}/p;d};/^>/!{H;$!d};x;s/\n/\\n/g;s|.*|s/&\\n*//g|p;$s|.*|s/\\n*$//|p;x;h;d' file1
sed -f - file2

这将从file1构建一个脚本,然后针对file2运行它。

脚本在file2中徘徊,然后使用file1的内容进行gobal替换。最后,它删除了内容删除导致的结束文件中的任何空行。

要查看从file1生成的脚本,请删除管道和第二个sed命令。

另一种方法是使用diff和sed:

 diff -e file2 file1 | sed 's/d/p/g' | sed -nf - file2