Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash awk:用另一个文件过滤文件的更优雅的方法_Bash_Parsing_Optimization_Awk_Bigdata - Fatal编程技术网

Bash awk:用另一个文件过滤文件的更优雅的方法

Bash awk:用另一个文件过滤文件的更优雅的方法,bash,parsing,optimization,awk,bigdata,Bash,Parsing,Optimization,Awk,Bigdata,由于我需要解析非常大的文件,所以我最近接近了速度非常快的awk。 我必须解析这种输入 ID 001R_FRG3G Reviewed; 256 AA. AC Q6GZX4; [...] SQ SEQUENCE 256 AA; 29735 MW; B4840739BF7D4121 CRC64; MAFSAEDVLK EYDRRRRMEA LLLSLYYPND RKLLDYKEWS PPRVQVECPK APVEWNNPPS

由于我需要解析非常大的文件,所以我最近接近了速度非常快的awk。 我必须解析这种输入

ID   001R_FRG3G              Reviewed;         256 AA.
AC   Q6GZX4;
[...]
SQ   SEQUENCE   256 AA;  29735 MW;  B4840739BF7D4121 CRC64;
     MAFSAEDVLK EYDRRRRMEA LLLSLYYPND RKLLDYKEWS PPRVQVECPK APVEWNNPPS
     EKGLIVGHFS GIKYKGEKAQ ASEVDVNKMC CWVSKFKDAM RRYQGIQTCK IPGKVLSDLD
     AKIKAYNLTV EGVEGFVRYS RVTKQHVAAF LKELRHSKQY ENVNLIHYIL TDKRVDIQHL
     EKDLVKDFKA LVESAHRMRQ GHMINVKYIL YQLLKKHGHG PDGPDILTVK TGSKGVLYDD
     SFRKIYTDLG WKFTPL
//
ID   002L_FRG3G              Reviewed;         320 AA.
AC   Q6GZX3;
[...]
SQ   SEQUENCE   320 AA;  34642 MW;  9E110808B6E328E0 CRC64;
     MSIIGATRLQ NDKSDTYSAG PCYAGGCSAF TPRGTCGKDW DLGEQTCASG FCTSQPLCAR
     IKKTQVCGLR YSSKGKDPLV SAEWDSRGAP YVRCTYDADL IDTQAQVDQF VSMFGESPSL
     AERYCMRGVK NTAGELVSRV SSDADPAGGW CRKWYSAHRG PDQDAALGSF CIKNPGAADC
     KCINRASDPV YQKVKTLHAY PDQCWYVPCA ADVGELKMGT QRDTPTNCPT QVCQIVFNML
     DDGSVTMDDV KNTINCDFSK YVPPPPPPKP TPPTPPTPPT PPTPPTPPTP PTPRPVHNRK
     VMFFVAGAVL VAILISTVRW
//
ID   004R_FRG3G              Reviewed;          60 AA.
AC   Q6GZX1; dog;
[...]
SQ   SEQUENCE   60 AA;  6514 MW;  12F072778EE6DFE4 CRC64;
     MNAKYDTDQG VGRMLFLGTI GLAVVVGGLM AYGYYYDGKT PSSGTSFHTA SPSFSSRYRY
…用这样的文件过滤它

Q6GZX4
dog
…要获得如下输出:

Q6GZX4 MAFSAEDVLKEYDRRRRMEALLLSLYYPNDRKLLDYKEWSPPRVQVECPKAPVEWNNPPSEKGLIVGHFSGIKYKGEKAQASEVDVNKMCCWVSKFKDAMRRYQGIQTCKIPGKVLSDLDAKIKAYNLTVEGVEGFVRYSRVTKQHVAAFLKELRHSKQYENVNLIHYILTDKRVDIQHLEKDLVKDFKALVESAHRMRQGHMINVKYILYQLLKKHGHGPDGPDILTVKTGSKGVLYDDSFRKIYTDLGWKFTPL    256
dog    MNAKYDTDQGVGRMLFLGTIGLAVVVGGLMAYGYYYDGKTPSSGTSFHTASPSFSSRYRY    60
为此,我提出了以下代码:

   BEGIN{
    while(getline<"filterFile.txt">0)B[$1];
}
{
    if ($1=="ID")
        len=$4;
    else{
        if ($1=="AC"){
            acc=0;
            line = substr($0,6,length($0)-6);
            split(line,A,"; ");

            for (i in A){
                if (A[i] in B){
                    acc=A[i];
                }
            }
            if (acc){
                printf acc"\t";
            }
        }
        if (acc){
            if(substr($0, 1, 5) == "     "){
                printf $1$2$3$4$5$6;
            }
            if ($1 == "//"){
                print "\t"len
            }   
        }
    }
}
开始{
而(getline0)B[$1];
}
{
如果($1==“ID”)
len=4美元;
否则{
如果($1==“AC”){
acc=0;
行=子行($0,6,长度($0)-6);
拆分(行,A,“;”);
为了(我在A){
if(B中的A[i]{
acc=A[i];
}
}
国际单项体育联合会(acc){
printf acc“\t”;
}
}
国际单项体育联合会(acc){
如果(substr($0,1,5)==“”){
printf$1$2$3$4$5$6;
}
如果($1==“/”){
打印“\t”透镜
}   
}
}
}
然而,由于我已经看到了许多使用awk完成类似任务的例子,我认为可能有一种更优雅、更有效的方法来完成它。但是我不能真正理解通常在互联网上找到的超级紧凑的例子。
由于这是我的输入、输出和代码,我认为这是一个从性能和编码风格方面了解更多awk优化的好机会,如果一些awk大师有时间和耐心来完成这项任务。

对于这类任务,一个想法是通过awk或sed传输第二个文件,以便动态创建一个解析大文件的新awk脚本。例如:

控制文件(f1):

数据(f2):

一开始的想法是:

sed 's/^\(.*\)$/\/\1\/ {print $2}/' f1 | awk -f - f2
(其中
-f-
表示:从标准输入而不是从命名文件中读取awk脚本)。

#!/usr/bin/perl
use warnings;
use strict;

open my $FILTER, '<', 'filterFile.txt' or die $!;
my %wanted;                # Hash of the wanted ids.
chomp, $wanted{$_} = 1 for <$FILTER>;

$/ = "//\n";               # Record separator.
while (<>) {
    my ($id_string) = /^ AC \s+ (.*) /mx;
    my @ids = split /\s*;\s*/, $id_string;

   if (my ($id) = grep $wanted{$_}, @ids) {
        print "$id\t";
        my ($seq) = /^ SQ \s+ .* $ ((?s:.*)) /mx;
        $seq =~ s/\s+//g;  # Remove whitespace.
        $seq =~ s=//$==;   # Remove the final //.
        print "$seq\t", length $seq, "\n";
    }
}
#/usr/bin/perl
使用警告;
严格使用;

打开我的$FILTER,一个带有不同字段分隔符的awk解决方案(这样,您可以避免使用
substr
split
):

开始{
而(getline0)过滤器[$1]=1;
FS=“[\t;]”OFS=“”;ORS=“”;
}
{
国际单项体育联合会(旗){
如果(len)
如果($1==“/”){
打印“\t”len“\n”;
flag=0;len=0;
}否则{
$1 = $1;
印刷品;
}
否则,如果($1==“SQ”)len=$3;
}如果($1==“AC”){
对于(i=1;++i
注意:此代码的设计目的不是简短,而是快速。这就是为什么我没有尝试删除嵌套的if/else条件,但我尝试尽可能减少整个文件的全局测试数。
然而,在我的第一个版本和几个基准测试之后进行了几次更改之后,我必须承认choroba perl版本要快一点。

可能不会比原始版本短很多,但是多个
awk
脚本将使代码更简单。第一个awk生成感兴趣的记录,第二个提取信息,第三个格式化

$ awk 'NR==FNR{keys[$0];next} 
              {RS="//";
               for(k in keys) 
                  if($0~k) 
                     {print "key",k; print $0}}' keys file
| awk '/key/{key=$2;f=0;;next} 
        /SQ/{f=1;print "\n\n"key,$3;next} 
           f{gsub(" ","");printf $0} 
         END{print}' 
| awk -vRS= -vOFS="\t" '{print $1,$3,$2}'
将打印

Q6GZX4  MAFSAEDVLKEYDRRRRMEALLLSLYYPNDRKLLDYKEWSPPRVQVECPKAPVEWNNPPSEKGLIVGHFSGIKYKGEKAQASEVDVNKMCCWVSKFKDAMRRYQGIQTCKIPGKVLSDLDAKIKAYNLTVEGVEGFVRYSRVTKQHVAAFLKELRHSKQYENVNLIHYILTDKRVDIQHLEKDLVKDFKALVESAHRMRQGHMINVKYILYQLLKKHGHGPDGPDILTVKTGSKGVLYDDSFRKIYTDLGWKFTPL       256
dog     MNAKYDTDQGVGRMLFLGTIGLAVVVGGLMAYGYYYDGKTPSSGTSFHTASPSFSSRYRY    60
awk'FNR==NR{aFilter[$1”;“]=$1;next}
/^AC/{
如果(String!~/^$/)打印采取“\t”String“\t”Len
take=“;String=“”

对于(i=2;i在Vim中,实际上只有一条直线可以找到模式:

/^AC.\{-}Q6GZX4;\_.\{-}\nSQ\_.\{-}\n\zs\_.\{-}\ze\/\//
其中
Q6GZX4;
是要查找的模式,以便匹配序列字符

上述措施基本上可以:

  • 搜索以
    AC
    开头(
    ^
    )的行,其后是
    Q6GZX4;
  • 按照(
    \\.\{-}
    )到以
    SQ
    开头的行(
    \nSQ
  • 然后转到下一行,忽略当前(
    \\\.\{-}\n
    )中的内容
  • 现在开始选择main(
    \zs
    ),它基本上就是一切(
    \\\\\.{-}
    ),直到(
    \ze
    )找到
    /
    模式
  • 然后执行常规Vim命令(
    norm
    ),选择模式(
    gn
    ),并将其拉入
    x
    寄存器(
    “xy
  • 您现在可以打印寄存器(
    echo@x
    )或从中删除空白字符
  • 这可以扩展到Ex编辑器脚本中,如下所示(例如
    cmd.Ex
    ):

    然后从命令行运行,如下所示:

    $ ex inputfile < cmd.ex
    Q6GZX4 MAFSAEDVLKEYDRRRRMEALLLSLYYPNDRKLLDYKEWSPPRVQVECPKAPVEWNNPPSEKGLIVGHFSGIKYKGEKAQASEVDVNKMCCWVSKFKDAMRRYQGIQTCKIPGKVLSDLDAKIKAYNLTVEGVEGFVRYSRVTKQHVAAFLKELRHSKQYENVNLIHYILTDKRVDIQHLEKDLVKDFKALVESAHRMRQGHMINVKYILYQLLKKHGHGPDGPDILTVKTGSKGVLYDDSFRKIYTDLGWKFTPL
    
    $ex inputfile

    上面的示例可以进一步扩展为多个文件或匹配项。

    您的代码看起来几乎没有问题。请保持简单,一次通过

    只有几点建议:

    1) 拆分前后的业务太混乱/脆弱。或许可以这样尝试:

            acc="";
            n=split($0,A,"[; ]+");
    
            for (i=2;i<=n;++i){
                if (A[i] in B){
                    acc=A[i];
                    break;
                }
            }
    
    更新一个可能的“优雅”:

    3)
    pattern{action}
    awk
    样式已经是if/then的一种形式,因此您可以避免许多外部if/then嵌套:

    $1="ID" {len=$4}
    $1="AC" {
        acc="";
        ...
        }
    acc {
        if(substr($0, 1, 5) == "     "){
          ...
        }
    

    抱歉,这可能更好,但我不太明白你在那里做了什么。另外,我的“f2”真的与之不同。谢谢你,但你真的确定这个解决方案比awk更快吗?我需要解析一个>10 Gb的文件,尝试对其进行基准测试。对我来说,它肯定更可读,因此更易于维护。
    /^AC.\{-}Q6GZX4;\_.\{-}\nSQ\_.\{-}\n\zs\_.\{-}\ze\/\//
    
    let s="Q6GZX4"
    exec '/^AC.\{-}' . s . ';\_.\{-}\nSQ\_.\{-}\n\zs\_.\{-}\ze\/\//norm gn"xy'
    let @x=substitute(@x,'\W','','g')
    silent redi>>/dev/stdout
    echon s . " " . @x
    redi END
    q!
    
    $ ex inputfile < cmd.ex
    Q6GZX4 MAFSAEDVLKEYDRRRRMEALLLSLYYPNDRKLLDYKEWSPPRVQVECPKAPVEWNNPPSEKGLIVGHFSGIKYKGEKAQASEVDVNKMCCWVSKFKDAMRRYQGIQTCKIPGKVLSDLDAKIKAYNLTVEGVEGFVRYSRVTKQHVAAFLKELRHSKQYENVNLIHYILTDKRVDIQHLEKDLVKDFKALVESAHRMRQGHMINVKYILYQLLKKHGHGPDGPDILTVKTGSKGVLYDDSFRKIYTDLGWKFTPL
    
            acc="";
            n=split($0,A,"[; ]+");
    
            for (i=2;i<=n;++i){
                if (A[i] in B){
                    acc=A[i];
                    break;
                }
            }
    
    printf "%s\t",acc";
    
    printf "%s%s%s%s%s%s",$1,$2,$3,$4,$5,$6;
    
    $1="ID" {len=$4}
    $1="AC" {
        acc="";
        ...
        }
    acc {
        if(substr($0, 1, 5) == "     "){
          ...
        }