awkの「inf」は「-inf」のようには機能しません。

awkの「inf」は「-inf」のようには機能しません。

単一の列番号ファイルが与えられると、呼び出されると、f次のAwkコードは最大値を返します。

cat f | awk    '   BEGIN {max = -inf}
                       {if ($1>max) max=$1} 
                   END { print max }
               '

最小値を求めるのと同じ方法で結果は出ません。

cat f | awk '
               BEGIN  {min = inf}
                  {if ($1<min) min=$1} 
               END {print min}
            '

ただし、 をinf使用せずに で始まるmin = [some large number]場合、数字が十分に大きい場合(ファイルの内容に応じて)、修正されたコードが機能します。

なぜそれがうまくいかず、ファイルに何があるのか​​を知らずにケースをケースのように処理するinf方法はありますか?minmax

答え1

これ実際仕事最善の解決策は、仮想の「最小」または「最大」数(この場合は使用中のフレームワークでは達成できない可能性がありますawk)ではなく、次のように最大/最小値を初期化することです。実際データ。これにより、常に意味のある結果が保証されます。

あなたの場合、ルールを追加して最初に見つかった値(つまり、最初の行のエントリ)を初期化してmaxそれぞれ使用できます。min

NR==1{min=$1}

あなたのスクリプトにawk。その後、最初の値がすでに最小値である場合、後続のテストはそれを処理せずに最終的に正しい結果を生成します。最大値検索にも同様に適用されるため、結合検索では次のことを宣言できます。

NR==1{max=min=$1}

infあなたの方法がうまくいかないのはなぜですか?そして@steeldriverがあなたの質問に対するコメントに良い説明を提供したawkようです-inf。完全性のためにまとめます。

  • では、awk変数は「動的に型付け」されます。つまり、使用方法に応じて、すべてが文字列または数字になる可能性があります(ただし、awk最後に使用された内容を「記憶」し、次の作業のためにその情報を保持します)。
  • コードで変数に関連する算術演算が見つかるたびに、そのawk変数の内容を数値として解釈して操作を実行しようとします。成功すると、そこから変数が数値として入力されます。
  • 何も割り当てられていない変数のデフォルト値は空の文字列であり、算術演算ではゼロと解釈されます。
  • これ変数名(*) inf特別な意味がないので、このようにawk使用するとのような算術式でゼロと評価される空変数である-inf。したがって、データがすべて正の場合、max変数がゼロに初期化された「最大検索」が機能します(したがって、負ではなく最小の数値)。-inf-inf
  • ただし、「最小検索」の問題では、この空の文字列を数値に自動的に変換することを保証する算術演算がないため、初期化は変数を空の文字列に初期min化します。inf
  • だから次の比較では

    if ($1<min) min=$1
    

    入力は$1文字列値と比較されるため、文字列awkとして処理され実行されます。$1事前編纂数字よりは比較してみてください。

  • しかし、事前編纂の観点からは、何もない空の文字列より「小さい」。min いいえ新しい値が割り当てられます。したがって、このEND部分では次のように述べる。

    print min
    

    (まだ)空の文字列を印刷します。

(*) バラよりSteven Kitの答えどのように内容を含む文字列"inf"実際に理解することができますawk

答え2

infGNU AWKのデフォルトの非POSIXモードでは特別な意味がないため、あなたのアプローチは機能しません。その結果、変数名として解釈され、変数に何も設定されていないため、その値は算術コンテキストでは0、文字列コンテキストでは空文字列です。したがって、コードは正の最大値(max算術コンテキストで初期化されるため)のみを探し、最小値(min文字列コンテキストで初期化されるため)は見つかりません。マネージャーミツバチの答えもっと学ぶ。

ファイル(またはストリーム)の最小値および/または最大値を決定するには、次のアドバイスに従ってください。マネージャーミツバチの答え

ただし、GNU AWKを使用している場合は、正または負の無限大で変数の初期化をlog(0)計算し、メソッドと同様の方法で使用できます。

BEGIN { max = log(0) }
$1 > max { max = $1 }
END { print max }
BEGIN { min = -log(0) }
$1 < min { min = $1 }
END { print min}

最初の行の値を初期化するのと比較して、このアプローチの唯一の利点は、処理される値がない場合に独自の結果を提供できることです。正または負の無限大は、結果として値が表示されなかったことを示す信頼できる指標になります。 (最初の行で初期化するときにゼロではなく空の文字列をチェックするなど、これを確認する別の方法があります。)

たとえば、POSIXモード(POSIXLY_CORRECT=1)でGNU AWKを使用するか、他のPOSIX準拠のAWKインタプリタを使用します。mawk"inf"ひもおかげで、算術コンテキストで無限大が生成されます。strtod:

BEGIN { max = "-inf" + 0 }
$1 > max { max = $1 }
END { print max }
BEGIN { min = "+inf" + 0 }
$1 < min { min = $1 }
END { print min}

答え3

実際、無限大には-inf +infandinfと の 3 つの値があります。単純な問題にさらに複雑さを追加するために、awkには引用符付きコード定数と引用符付きコード定数があります。

何を意味するのかを説明するには、次のことを試してください(awk 4.2.1(現在のDebian 10)のシェルコード)。

for cmd in original-awk "busybox awk" mawk nawk awk; do
    printf '%-6.5s' "$cmd"
    $cmd 'BEGIN {
        a="-inf";b="+inf";c="inf";
        d= -inf ;e= +inf; f= inf;
        printf "-∞%4s%4s +∞%4s%4s ∞%4s%4s | -∞%4s%4s +∞%4s%4s ∞%4s%4s\n",a,a+0,b,b+0,c,c+0,d,d+0,e,e+0,f,f+0}
    ' file

取得するには:

bawk  -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞       0 ∞       0
busyb -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞   0   0 ∞       0
mawk  -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞   0   0 ∞       0
nawk  -∞-inf-inf +∞+inf inf ∞ inf   0 | -∞   0   0 +∞   0   0 ∞       0
gawk  -∞-inf-inf +∞+inf inf ∞ inf   0 | -∞   0   0 +∞   0   0 ∞       0

この表は、引用符付き変数の割り当てと引用符付き変数の割り当て(abcdef)を示しています。
いずれの場合も、awkは値を読み取り、数値(var + 0)に変換します。

"-inf"これは、aが数字の場合でもそのまま残り、aは数字(符号なし)"+inf"に変換され、参照されたaは実装に応じて、またはそれになることができます(nawkおよびgawkでは0)。inf"inf"inf0

引用符がない場合は-inf両方とも+infなります(空の文字列 ""と解釈され、に変換される0bawkを除く)。+∞0

奇妙なことは、引用符がなければ、すべてがinf空の文字列として解釈されるということです。

ただし、すべて引用符なしで-inf使用すると+infゼロになります。infvar+0

したがって、目的の操作には引用符が必要であり、"-inf"絶対に"+inf"次は必要ありませんinf

cat file | awk  '  BEGIN { max = "-inf"+0; min = "+inf"+0 }
                         { if ($1>max) max=$1
                           if ($1<min) min=$1
                         } 
                   END   { print min, max }
                '

おそらくこれを理解するより簡単な(移植不可能な方法)は次のとおりです。

gawk 'BEGIN{
               a="-inf";b="+inf";c="inf";
               d= -inf ;e= +inf; f= inf;

               print a,   typeof(a),   b,   typeof(b),   c,   typeof(c)
               print a+0, typeof(a+0), b+0, typeof(b+0), c+0, typeof(c+0)

               print d,typeof(d),e,typeof(e),f,typeof(f)
               print d+0,typeof(d+0),e+0,typeof(e+0),f+0,typeof(f+0)
      }'

以下を印刷します。

-inf string +inf string inf string
-inf number inf number 0 number
0 number 0 number  unassigned
0 number 0 number 0 number

もちろん、正確で移植可能な解決策は、max最初から変数に値を割り当てることです。min

cat file | awk  '  NR==1 { min = max = $1 }
                         { if ($1>max) max=$1
                           if ($1<min) min=$1
                         } 
                   END   { print min, max }
                '

---

説明するawkマニュアルから例:

  • --posixコマンドラインオプションを使用すると、gawk「そのままにしておく」ことができます。文字列値はシステムライブラリのstrtod()関数に直接渡され、正常に数値を返すとその値が使用されます。定義によると、結果は他のシステムに移植することはできません。彼らも少し驚くべきです。
$ echo influence | gawk --posix '{ print $1 + 0 }'
  -| inf
$ echo 0xDeadBeef | gawk --posix '{ print $1 + 0 }'
  -| 3735928559
  • それ以外の場合は、--posixgawk+inf」、「-inf」、「+nan」、および「-nan」の4つの文字列値が特別に解釈され、その特殊値が生成されます。先行記号は、ユーザー(およびユーザー)に値が実際には数値であるという信号として機能します。 16進浮動小数点はサポートされていません(推奨されていない--non-decimal-dataも使用しない限り)。たとえば、
$ echo nanny | gawk '{ print $1 + 0 }'
  -| 0
$ echo +nan | gawk '{ print $1 + 0 }'
  -| +nan
$ echo 0xDeadBeef | gawk '{ print $1 + 0 }'
  -| 0

gawk4 つの特殊値の場合は無視します。したがって、「+nan」と「+NaN」は同じです。

入力の処理に加えて、gawk値がNaNまたは無限大の場合は、出力に「正しい」値を印刷する必要があります。バージョン4.2.2以降、これらの値の場合は、上記gawkの4つの文字列(「+inf」、「-inf」、「+nan」、または「-nan」)のいずれかが印刷されます。同様に、POSIXモードでは、gawkシステムC関数の結果は値の形式文字列(何でも)を使用して印刷されます。printf()%g

関連情報