awkを実行するときにファイルの文字列を値として扱うには?

awkを実行するときにファイルの文字列を値として扱うには?

文書一部の欠落データポイントの値があり、欠落している値はと表示されます****。 10未満の値を持つ7つの連続した列を持つ行を選択する必要があります。私が走るときスクリプト****また、連続列に対応する行を提供します。

**** すべてをより高い値に置き換えることで、簡単に問題を解決できます。しかし、入力ファイルを変更したくありません。私のスクリプトが****数字(より大きい)として扱うように何かをしたいと思います10 i.e. str=****=100。どうすればいいですか?

入力例consecutive7pointDown10.input-

2     3    4    5    6    7    8   0  12   14   23
2     3    4    12   6    7    8   0  1     2   23
**** **** **** **** **** **** **** 8 ****  **** 12

私のスクリプトの結果consecutive7pointDown10.output-

2     3    4    5    6    7    8    0    12    14   23
**** **** **** **** **** **** ****  8   ****  ****  12

ただし、予想出力

2     3    4    5    6    7    8    0    12  14   23

私のスクリプトconsecutive7pointDown10は次のとおりです -

#!/bin/bash
########################################################################################################################
# This script results rows having at most 10°C in consecutive at most 7 points.
# input = scriptname.input
# output = scriptname.output
########################################################################################################################
input=`basename "$0"`.input
output=`basename "$0"`.output
awk '{
    for(i=4;i<=34-6;i++)
        {   
            if($i<=10 && $(i+1)<=10 && $(i+2)<=10 && $(i+3)<=10 && $(i+4)<=10 && $(i+5)<=10 && $(i+6)<=10)
            {
                print
                next
            }
        }
}' $input > $output

答え1

awk '/(\<[0-9]\s+){7}/{print}' input.txt

または

sed -rn '/(\b[0-9]\s{1,}){7}/p' input.txt

仕事をします。

awkの説明(sedのロジックは同じ):

  • /(\<[0-9]\s+){7}/{print}- パターンを含む行を印刷します。

  • \<- 単語の境界と一致します。つまり、右側の文字が「単語」文字で、左側の文字が「非単語」文字の場合は一致します。

  • [0-9]\s+0- に1桁の数字9、その後に1つ以上のスペースが続きます。
  • (\<[0-9]\s+){7}-\<[0-9]\s+パターンが7回繰り返されると一致します。

入力する

2     3    4    5    6    7    8   0  12   14   23
2     3    4    12   6    7    8   0  1     2   23
**** **** **** **** **** **** **** 8 ****  **** 12

出力

2     3    4    5    6    7    8   0  12   14   23

編集する:

精度が1の浮動小数点数(9.2、8.1、7.5など)の場合。

awk '/(\<[0-9]\.[0-9](\s+|$)){7}/{print}' input.txt

答え2

awkすべての条件が満たされた場合に増加するか、逆の場合にリセットされるフラグを使用すると、連続した7つの列を繰り返しチェックすることを回避できます。

awk '{c=0; split($0,arr,/ +/);
    for(x in arr) if(arr[x]<10 && arr[x]>=0) {
        if(++c==7){ print $0; next } }else{c=0} }' infile

ここではawkの分割機能« split(string, array [, fieldsep [, seps ] ])»行($0行全体を表す)をawk1つ以上のスペースで区切られた名前付き配列に分割します。arr

次に配列要素を繰り返し、その値が10から0の間であることを確認してからcallというフラグを増やしc、7に達すると行を印刷します(7つの連続要素(列)が条件を満たすことを意味します)。フラグは0に設定されます。


または、行を配列に分割せずに同じ方法で実行します。

awk '{c=0; for(i=1;i<=NF;i++) if($i<10 && $i>=0) {
    if(++c==7){ print $0; next } }else{c=0} }' infile

4列から最後までフィルタリングするには、次のものが必要です。NFで始まる各行のフィールド/列数を示しますawk

$ time awk '{c=0; for(i=4;i<=NF;i++) if($i<10 && $i>=0) {
    if(++c==7) {print $0; next} }else{c=0} }' infile
real    0m0.317s
user    0m0.156s
sys     0m0.172s

または、正規表現モードで再適用されます。オリジナルファイル浮動小数点のみが含まれている場合(フラグで使用する場合)よりもgrep効率的で約6倍速い次のコマンドを使用できます。awk-PGrep -E、Sed -E - "[x]{1,9999}"を使用するとパフォーマンスが低下しますが、なぜですか?)、しかしawk範囲を変更することができますので、ソリューションの柔軟性が与えられた場合は、+ 2桁の整数/浮動/混合の場合に機能します。

$ time grep -P '([^\d]\d\.\d[^\d]){7}' infile
real    0m0.060s
user    0m0.016s
sys     0m0.031s

または他の方法で:

$ time grep -P '(\s+\d\.\d\s+){7}' infile
real    0m0.057s
user    0m0.000s
sys     0m0.031s

grepまたはsed以下との互換性awk

$ time grep -E '([^0-9][0-9]\.[0-9][^0-9]){7}' infile
real    0m0.419s
user    0m0.375s
sys     0m0.063s
$ time sed -En '/([^0-9][0-9]\.[0-9][^0-9]){7}/p' infile
real    0m0.367s
user    0m0.172s
sys     0m0.203s
$ time awk '/([^0-9][0-9]\.[0-9][^0-9]){7}/' infile
real    0m0.361s
user    0m0.219s
sys     0m0.172s

関連情報