特定の行の値に基づいて列を選択/抽出

特定の行の値に基づいて列を選択/抽出

以下はサンプルテキストファイルです。

A B C D E F G
1 2 3 4 5 6 7
2 3 4 5 6 7 8
3 4 5 6 7 8 9

3行目の値である2 3 4 5 6 7 8に基づいて特定の列を抽出したいと思います。 3行目で5より大きい値を持つすべての列を抽出したいとします。最後の3列になります。したがって、私の目標は、以下を選択して生成することです。

E F G
5 6 7
6 7 8
7 8 9

これは私のコードです。

NR==3 {
    for (i=1; i<=NF; i++) {
        if ($i > 5)   x[j++] = i
    }
}
NR>= 1 {
  for (i=0 ;  i < j-1; i++ )
     printf("%s ",$x[i])
  printf("%s\n",$x[j-1])
}

ただし、これにより次のような結果が得られます。

A B C D E F G
1 2 3 4 5 6 7
6 7 8
7 8 9

私が逃したものは何ですか?

答え1

次のことができます。

code=$(
  awk '
    NR == 3 {
      for (i=1; i<=NF; i++)
        if ($i > 5) { printf "%s", sep "$" i; sep="," }
      exit sep == ""
    }' file
) &&
  awk "{print $code}" file

つまり、awk同じファイルから2回呼び出すことです。最初の行は3行目を読み、2番目の呼び出しのawkコードを構成します。 3行目を処理した後に終了するため、ファイル全体を完全に読み取ることはありません。次の結果が出力されるため、次の$5,$6,$7呼び出しawkは次のようになります。

awk '{print $5,$6,$7}' file

答え2

共有する別のawkソリューションがあります。

cat > extract.columns.awk   
BEGIN {   
  infil=ARGV[1]  
    while (getline < infil > 0)  
      if (++n==3)  
      {  
        for(i=1;i<=NF;i++)  
            if ($(i) > 5) x[++j]=i  
    }  
close(infil)    
}  
{  
    for (i=1;i<j;i++)  
    printf("%s ",$x[i])  
    printf("%s\n",$x[j])  
}  

awk -f extract.columns.awk ファイル

答え3

以下のコードに従ってファイル名を2回参照してください。

awk 'NR == FNR{if(FNR == line) {for(i=1; i<=NF; i++) {if($i > lmt) a[i]} close(FILENAME)} next}
{for(i=1; i<=NF; i++) {for(i in a) {out = (out == "") ? $i : (out FS $i)}}
  print out; out=""}' line=3 lmt=5 file file

関連情報