4

ファイルから特定のフィールドを抽出しようとしています。基本的に、一致した式を含むフィールドのみを出力し、一致したレコードの後に​​出力を開始します。

これは私の入力例です。フィールドの順序が異なる場合や、一致させようとしているヘッダーの前の行数が異なる場合があります。

cut コマンドと sed コマンドを使用してこれを実現する方法を見つけるのに苦労していましたが、awk メソッドを見つけることができませんでした。

CGATS.17
FORMAT_VERSION  1
KEYWORD "SampleID"
KEYWORD "SAMPLE_NAME"
NUMBER_OF_FIELDS    45
WEIGHTING_FUNCTION "ILLUMINANT, D50"
WEIGHTING_FUNCTION "OBSERVER, 2 degree"
BEGIN_DATA_FORMAT
SampleID    SAMPLE_NAME CMYK_C  CMYK_M  CMYK_Y  CMYK_K  LAB_L   LAB_A   LAB_B   nm380   nm390   nm400
END_DATA_FORMAT
NUMBER_OF_SETS  182
BEGIN_DATA
1   1   40  40  40  0   62.5    6.98    4.09    0.195213    0.205916    0.212827
2   2   0   40  40  0   73.69   25.48   24.89   0.200109    0.211081    0.218222
3   3   40  40  0   0   63.95   12.14   -20.91  0.346069    0.365042    0.377148
4   4   0   70  70  0   58.91   47.69   35.54   0.080033    0.084421    0.087317
END_DATA

これは私が使用したダーティ コードで、フィールド ヘッダーの条件付き検索を行わずにほとんどの作業を行いました。awk コマンドは、出力を囲む空の行を削除するだけです。

cut -f 7-9 -s input.txt | 
sed -E 's/(LAB_.)//g' |
awk 'NF' > file.txt

私が期待する出力は次のようになります。タブ区切りのままで、(LAB_.) のすぐ下から始まるフィールドの値のみが含まれます。

62.5    6.98    4.09
73.69   25.48   24.89
63.95   12.14   -20.91
58.91   47.69   35.54
4

3 に答える 3

1

脚本:

#!/usr/bin/awk -f

# We look for line starting with BEGIN_DATA_FORMAT do the getline function and 
# store location of fields that have "LAB" in their name on the next line.

/^BEGIN_DATA_FORMAT/{
        getline
            for (i=1;i<=NF;i++) 
                    if ($i~/LAB/) a[i]=$i
                } 

# In this regex range we look for lines that have more than 2 fields. For those 
# lines we loop thru each field and see if the location matches to the ones 
# captured in our earlier array (i.e location number of fields that have "LAB" 
# in their name). If we find a match we print those fields. 

/^BEGIN_DATA$/,/^END_DATA$/{
             s="";
             if (NF<2) next; else 
                for (j in a)
            s=s?s"\t"$j:$j
            print s; 
                 }

テスト:

[jaypal:~/Temp] ./script.awk file
62.5    6.98    4.09    
73.69   25.48   24.89   
63.95   12.14   -20.91  
58.91   47.69   35.54   
于 2012-01-21T03:41:02.657 に答える
1

別の awk スクリプト:

 awk '/^BEGIN_DATA_FORMAT/{getline;f=NF;for(i=1;i<=NF;i++)if($i~/^LAB_[LAB]/)l[i]++;} 
/^BEGIN_DATA/,/^END_DATA/ && NF==f{s=""; for(x in l)s=s?s"\t"$x:$x; print s;}' input

入力例の出力:

62.5    6.98    4.09
73.69   25.48   24.89
63.95   12.14   -20.91
58.91   47.69   35.54

上記の awk スクリプトに関する注意事項:

  • ヘッダー処理は @JayPal のソリューションと似ていますが、わずかに異なります。列の順序が異なる可能性があると述べたので、ヘッダーの一致のために、awk スクリプトは「BEGIN_DATA_FORMAT」の次の行を検索しました。見出しの 1 列目は SampleID 以外の可能性があるためです。

  • 出力では、予想どおり、値のみ ([タブ] で区切られている) が出力されますが、ヘッダーは出力されません。列の順序が可変であると言った場合、ヘッダー情報が失われる可能性があります。たとえば、A である LAB_L はどの列ですか? など。本当に必要な場合、これは簡単に実行できます。

于 2012-01-21T21:35:13.320 に答える
0

これはあなたのために働くかもしれません:

 sed '/^BEGIN_DATA\>/,/^END_DATA\>/{//d;s/\(\S*\s*\)\{6\}\(\S*\s*\S*\s*\S*\).*/\2/p};d' file

またはと一緒にcut

cut -f7-9 file | sed '/^\([-.0-9]*\s*[-.0-9]*\s*[-.0-9.]*$\)/!d'

または(ただし、ここでは入力ファイルの形式を推測しています):

sed 's/\s*$//' file | cut -f7-9 | sed '/^BEGIN_DATA$/,/^END_DATA$/{//d;p};d'
于 2012-01-21T08:56:15.427 に答える