'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).

더 큰 숫자를 변환하는 방법은 무엇입니까?

처리해야 할 숫자가 너무 많습니다(한 줄에 하나의 숫자, 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 bashPOSIX는 읽지 마십시오.) 예를 들어 다음 12ab34과 같이 반환됩니다.12AB34

두 경우 모두 { … }중괄호는 수정자를 변수에 바인딩합니다. 변수의 값만 반환되고 그 뒤에 두 개의 위쪽 화살표/캐럿 문자가 옵니다 "$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을 두 번째 인수로 사용하는 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 회선은 빨라야 합니다. 나는 5,578만 줄의 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초가 걸렸습니다.

관련 정보