GNU awkの実装制限が実際には機能しないように見えるのはなぜですか?

GNU awkの実装制限が実際には機能しないように見えるのはなぜですか?

このページGNU awk実装の制限については、フィールドサイズとリテラル文字列サイズの制限が挙げられますMAX_INT

ただし、長い文字列リテラルを変数として宣言し、関数を使用して長さを見つけようとすると、length文字列の長さが308文字を超えると関数が中断されるようです。以下の例:

BEGIN {
  avar=1234... #309 characters
  print length(avar) #prints 3 but prints right length when length < 309
} 

ただし、次のコマンドラインは1000文字まで機能します。

echo 1234... | awk '{print length($1)}' #tested and works for 1000 characters

CentOS 7システムを使用しており、awkのバージョンは4.0.2です。

この違いが発生する理由に関する提案はありますか?

ベストアンサー1

やりたいことを繰り返すのは簡単です。

awk 'BEGIN {
  avar='"$(printf '%0200d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
} '

これは0 1、200個のゼロからなる完全なリストがawkによって単一に変換されることを意味します0。これは次のような意味のようです。0が200個ある整数を書きます。

別の値を指定してみましょう(8の後に0が200個あります)。

➤ awk 'BEGIN {
  avar='"$(printf '8%0200d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
} '
799999999999999975786497770008289327579602620364018901185934007602774787484432604273570707237650014944220099327791059265457085874946227877115080328377919022968188728534319854489454506449337030839107584 201

これはの浮動小数点近似値です8e200。これは次のことで簡単に確認できます。

➤ awk 'BEGIN {
  avar='"$(printf '8%0200d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
  printf "%15e\n",avar
} '
799999999999999975786497770008289327579602620364018901185934007602774787484432604273570707237650014944220099327791059265457085874946227877115080328377919022968188728534319854489454506449337030839107584 201
  8.000000e+200

したがって、コード割り当て()で指定された数値はavar=数値として(正しく)処理されます。二重浮動小数点数は、最大308までの指数のみを格納できます(非正規数字を除く)。したがって、308ビットを超える値は浮動小数点数に変換できません。

➤ ➤ awk 'BEGIN {
  avar='"$(printf '8%0308d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
  printf "%15e\n",avar
} '
inf 3
            inf

ただし、文字列なのでavar="..."二重引用符( )で囲んでも問題はありません。

➤ awk 'BEGIN {
  avar="'"$(printf '8%0600d' 0)"'" #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
} '
8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 601

データがパイプ(またはファイル)から来る場合、データは文字列と見なされ(data + 0または同様の数値に変換されない限り)、その長さは文字数です。

$ printf '8%02000d0\n' 0 | awk '{print length($1)}'
2002

おすすめ記事