awkが数値でない場合はエラーを生成します。

awkが数値でない場合はエラーを生成します。

ファイルの列を合計するプログラムがあります。

awk -v col=2 '{sum+=$col}END{print sum}' input-file

しかし、ここに問題があります。数値データがない場合、または数値が欠落しているファイルを指定した場合は、それをゼロと解釈します。

フィールドの1つを数値に解析できない場合は、エラーが発生したいと思います。

入力例は次のとおりです。

bob 1
dave 2
alice 3.5
foo bar

「bar」は数字ではないので、エラーを無視するのではなく、エラーが発生したいと思います。

答え1

これをテストする合理的な方法は、次のようなテストを使用してフィールドを比較することです。strtod、どちらがawkの使い方文字列を数値に変換:

$2 !~ / *[+-]?[[:digit:]]/ { print "NAN: " $2; exit 1; }

上記とstrtodの違いは、INFINITYまたはNANを「数値」と見なさないことです。 awkのデフォルトのフィールド分割動作によっては、前の空白の要件が軽減されることがあります。つまり、フィールドには先行スペースは含まれません。

$2 !~ /[+-]?[[:digit:]]/ { print "NAN: " $2; exit 1; }

Stéphaneのコメントここに答えてください:

$2 !~ /^[+-]?([[:digit:]]*\.?[[:digit:]]*([eE][-+]?[[:digit:]]+)?|0[xX][[:xdigit:]]*\.?[[:xdigit:]]*([pP][-+]?[[:digit:]]+)?)$/ { print "NAN: " $2; exit 1; }

やや良い読みやすさのために、正規表現は次のようになります。

/^[+-]?([[:digit:]]*\.?[[:digit:]]*([eE][-+]?[[:digit:]]+)?|\
        0[xX][[:xdigit:]]*\.?[[:xdigit:]]*([pP][-+]?[[:digit:]]+)?)$/

...目的は、可能な前に+または-を許可し、その後に浮動小数点または16進数が続くことを許可することです。浮動小数点数には、オプションの先行数字、オプションの区切り記号(ここではピリオドで固定.)、その後に数字、オプションで指数が続きます。 16進数は0xまたはで始まり、0Xその後に16進数、区切り記号、追加の16進数字が続き、オプションで「2乗」(指数)が続く必要があります。 2番目のフィールド全体は、次のいずれかの形式と一致する必要があります(^およびによって固定されています$)。この質問の目的のために、NANおよびINFINITYオプションはここで省略されています。

もう1つのオプションは、数値変換を強制し、それを0と比較し、オプションの+または-で始まる場合、元の入力を0に変換する入力とさらに比較してから0または次に続くことです。ピリオドと0:

{ number=0 + $2;
  if (!number && $2 !~ /^[+-]?(0+)|\.0+/)
    print "NAN: "$2;
}

答え2

私はこれで終わりました:

awk -v col=$col '
typeof($col) != "strnum" {
    print "Error on line " NR ": " $col " is not numeric"
    noprint=1
    exit 1
}
{
    sum+=$col
}
END {
    if(!noprint)
        print sum
}' $file

これはGNU awk拡張であるtypeofを使用します。typeof($col)有効な数値の場合は「strnum」を返し$col、それ以外の場合は「未割り当て」を返します。

バラより awk変数の型を確認できますか?

答え3

awk -v col=2 '
    $col+0==0 && $col!~/^[+-]?0/ { print "bad number " $col > "/dev/stderr" } 
    {sum+=$col}
    END{print sum}' input-file

.0を処理したり、有効な表現として使用したい場合は、.0e+33それを複雑にすることができます。文字列を数値に変換すると、末尾のゴミ(またはすべて14と等しい)0は無視されます。awk"1.4e1e3"+0"1.4e1.e7"+0"14+13"+0

答え4

私が使用する小さな秘密は、文字列から平方根を求めることです。awk正しい結果を得るために最善の努力を払うので、末尾のゼロが数値でない場合、この方法は適切ではありません。

if ( sqrt(_varname) ) {
 print "this " _varname " is a (positive) number"
} else {
 print "this " _varname " is not a number..."
}

関連情報