
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
必要なので、これを行います。bc
0x
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秒かかりました。