'mawk'を使用して16進数を範囲外の10進数に変換する

'mawk'を使用して16進数を範囲外の10進数に変換する

16進数が比較的小さい場合は、次のものを使用できます。

echo 0xFF| mawk '{ printf "%d\n", $1}'

16進数を10進数に変換します。

16進数が非常に大きい場合、それはmawk機能しなくなります。

echo 0x8110D248 | mawk '{ printf "%d\n", $1 }'

出力2147483647(間違ったものと2147483647同じ0x7FFFFFFF)。

より大きな数字を変換するには?

処理する数字が多すぎます(1行に1つの数字、10M以上)。たとえば、0xFF\n 0x1A\n 0x25\nこの場合どうすれば処理できますか?合格xargs?もっと良い方法がありますか?xargs本当に遅いです。

答え1

ランダムに大きい数字のより良いコマンドはですbc。変換を行う機能です。

hextodec() {
    local hex="${1#0x}"
    printf "ibase=16; %s\n" "${hex^^}" | bc
}

hextodec 0x8110D248
2165363272

ここでは、変数を使用するときに変数値を操作する奇妙な機能を使用しています。

  • "${1#0x}"-"$1"予想通り、これは関数の最初のパラメータを参照します。#修飾子です(man bash例:参照または読み取りPOSIX) 値の先頭から次の式を削除します。たとえば、0xab12これは次のように返されます。ab12
  • "${hex^^}"-"$hex"アルファベット文字が大文字にマップされた値を参照しますが返します。 (これはbash拡張なので読み取らman bashれますが、POSIXは読みません。)たとえば、次のよう12ab34に返されます。12AB34

どちらの場合も、中{ … }括弧は修飾子を変数にバインドします。変数の値のみが返され、その後に2つの上向き矢印/カラット文字が続きます"$hex^^"$hex

答え2

mawk問題は内部的に符号付き32ビット整数を使用するため、2 31 -1(つまり2147483647)より大きい整数を表すことができないという事実に由来します。

すべてのサイズの16進ファイルをストリーミングするには、各ファイルを10進数に変換します。

{
    echo 'ibase=16'
    sed -e 'y/xabcdef/XABCDEF/' -e 's/^0X//'
} | bc

最初ibase=16に送信され、bcユーティリティに16進数を読み取るように指示します。その後、16進文字を大文字に変換し、ファイルから数字の接頭辞をsed削除するために使用されます。接頭辞がなく大文字の16進数が0x必要なので、これを行います。bc0x

fileコンテンツを含むファイルが与えられた場合

0xFF
0x1A
0x25
0x7FFFFFFF
0x8110D248
0x8110D2487FFFFFFF

...パイプが出力されます

255
26
37
2147483647
2165363272
9300164439347036159

パイプを通常のストリームシェル関数として書き換えることもできます。

hex2dec () {
    { echo 'ibase=16'; sed -e 'y/xabcdef/XABCDEF/' -e 's/^0X//'; } | bc
}


hex2dec <file

# Or...

some-process-producing-data |
some-filter-extracting-hexadecimal-numbers |
hex2dec |
while IFS= read -r number
    # use the decimal number in "$number" here.
done

答え3

@Stephane Chazelasが提案したように、perlのhex()組み込み関数を使用して、bignumモジュールを使用して16進→10進変換を実行できます。

$ perl -Mbignum -lpe '$_=hex' file

すべての16進数の前に0xまたは0Xが付いている場合は、組み込みの8進数を使用することもできます。

$ perl -Mbignum -lpe '$_=oct' file

ファイルからデータを読み取ることができるGNU dcデスクトップ電卓を使用できます。ただし、dcを呼び出す前に、dcが要求するように大文字の16進表記に切り替えて、16進文字列から先行0xを削除します。次に、入力基数を16(16i)に設定し、数字のみを印刷します(デフォルトは10です)。

< file \
tr a-fx A-FX |
cut -d "X" -f 2 |
dc -e "16i [q]sq
[?z0=qpcz0=?]s?
l?x
"

16を2番目の引数として使用するint()組み込み関数を使用すると、最初の引数である16進文字列を対応する10進数に変換します。

python3 -c 'import sys
with open(sys.argv[1]) as f:
  for l in f:
    print(int(l.strip(),16))
' file

答え4

声明について

mawk...したがって、2^31-1より大きい整数(例:2147483647)を表しません。

存在する@彼らの答え:この言葉は間違っていました。倍精度符号なし整数制限である2 53 -1までの16進数を読み取って印刷できます。

 echo '0x1234BEEF9CAFE7' \
 \
 | mawk '{ CONVFMT=OFMT="%.20g"; 
       print a=+(       substr($0,1,length($0)-8)),\
             b=+(("0x")(substr($0,1+length($0)-8))),\
             c=2^32*a+b,\
             sprintf("0x%X%.8X",a,b) }'

1193150 4020023271 5124544249245671 0x1234BEEF9CAFE7

または、より安全な方法 - 上側を16 7に、下側を16 6に分割することです。

echo '0x1234BEEF9CAFE7' | mawk '{ CONVFMT=OFMT="%.20g"; OFS="\f"; n=length(x=$0)
print a=+(       substr(x,1,n-6)),
      b=+(("0x")(substr(x,1+n-6))),
      c=2^24*a+b,
      sprintf("0x%X%.6X",a,b) }'
 
305446639
         10268647
                 5124544249245671
                                 0x1234BEEF9CAFE7

ndigits以下は、目的の16進数の下限値を取得するためにパラメータを簡単に調整できるより一般的なバージョンです。

 echo '0x1234BEEF9CAFE7' \
  \
  | mawk '{ CONVFMT=OFMT="%.20g"; 
            OFS="\f"; 

            w=length(x=$0); ndigits=7; # enter 6, 7, or 8

print a=+(       substr(x,1,w-ndigits)),
      b=+(("0x")(substr(x,1+w-ndigits))),
      c=(16^ndigits)*a+b,
      sprintf("0x%X%.*X",a,ndigits,b) }'

19090414
        261926887
                 5124544249245671
                                 0x1234BEEF9CAFE7

10Mラインは速くなければなりません。私は5578万行の16進数を含むランダムなテストファイルを作成しました。各行は13個の16進数で構成されています。

 % echo; ( time (  pvE0 < test_hex_list_01.txt| mawk 'BEGIN { CONVFMT=OFMT="%.20g"; const16=16^(ndigits=7) } { printf("%.f\n",const16*(a=+substr(x=$0,1,(w=length(x))-ndigits))+(b=+("0x"substr(x,1+w-ndigits))),a,ndigits,b) }' )) | pvE9 > test_hex_list_01_output_mawk_short.txt ; echo  

     out9: 2.22MiB 0:00:00 [22.1MiB/s] [22.1MiB/s] [<=>                                ]
      in0:  851MiB 0:00:39 [21.5MiB/s] [21.5MiB/s] [=================>] 100%            
     out9:  887MiB 0:00:39 [22.6MiB/s] [22.4MiB/s] [  <=>                              ]
( pvE 0.1 in0 < test_hex_list_01.txt | mawk ; )  39.20s user 0.94s system 101% cpu 39.64     out9:  887MiB 0:00:39 [22.4MiB/s] [22.4MiB/s] [ <=>                               ]
    
 % awkwc5 < test_hex_list_01.txt 
    
rows       = 55,779,444. | UTF8 chars = 892,471,099. | bytes      = 892,471,099.

約5,600万行の16進数を完了するのにわずか39.2秒かかりました。

関連情報