ファイルの列を合計するプログラムがあります。
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..."
}