Konwertuj liczbę dziesiętną na szesnastkową w skrypcie powłoki UNIX

110

Czego mogę użyć w skrypcie powłoki UNIX do konwersji liczb dziesiętnych na szesnastkowe? Myślałem, że od to załatwi, ale nie zdaje sobie sprawy, że karmię go reprezentacjami liczb w ASCII.

printf? Obrzydliwy! Używam go na razie, ale co jeszcze jest dostępne?

skiphoppy
źródło
8
Muszę zapytać, co jest obrzydliwego w printf? Wiele popularnych języków programowania obsługuje formatowanie podobne do printf, więc poniższe rozwiązania printf z pewnością byłyby najłatwiejsze do zrozumienia dla programistów.
Michael Scheper
4
Chłopie, nie wiem - to było pięć lat temu! Myślę, że może myślałem, że to nie była prawdziwa skorupa czy coś.
skiphoppy

Odpowiedzi:

108
echo "obase=16; 34" | bc

Jeśli chcesz przefiltrować cały plik liczb całkowitych, po jednej w każdym wierszu:

( echo "obase=16" ; cat file_of_integers ) | bc
Bill Karwin
źródło
1
Spojrzałem na bc (1) i dc (1) i przegapiłem to.
Keltia,
3
@skiphoppy: Jeśli napiszesz: echo "obase = 16; 12 34 56" | bc otrzymujesz 1E240, dokładnie tak samo, jak napisałeś: echo "obase = 16; 123456" | pne. Tak więc sposobem radzenia sobie z dowolnymi liczbami całkowitymi znajdującymi się w jednym wierszu jest umieszczenie każdej liczby w osobnym wierszu: tr '' '\ 015' <input | bc (odwzorowuj puste miejsca na znaki nowej linii).
Jonathan Leffler,
1
To jest wielki, jeśli zdarzy się, że „BC”, ale „printf” jest częścią bash sama
fuzzyTew
1
@Bill Karwin, czy zsh, czy busybox, ale może nie jakaś powłoka, której nie próbowałem? Nie instaluję już zwykłego sh, ale najwyraźniej skiphoppy szuka innych opcji
fuzzyTew
2
@ Sridhar-Sarnobat, jest to liczba dziesiętna na szesnastkową. Zakładam, że masz na myśli konwersję hex na dec. Aby to zrobić, ustaw ibase=16. Możesz przeczytać podręcznik bc, aby uzyskać więcej informacji.
Bill Karwin,
186

Próbowałeś printf(1)?

printf "%x\n" 34
22

Prawdopodobnie istnieją sposoby na zrobienie tego za pomocą wbudowanych funkcji we wszystkich powłokach, ale byłoby to mniej przenośne. Nie sprawdzałem specyfikacji POSIX sh, aby zobaczyć, czy ma takie możliwości.

Keltia
źródło
5
Nie ma o wiele więcej POSIX niż printf. Działa to nawet w „sh”.
Orwellophile
4
printf nie jest arbitralną precyzją. bcjest. na przykład, przyjmując 238862874857408875879219909679752457540jako dane wejściowe, printf daje nam „Wynik za duży”. metoda BC sprawdza się świetnie w przypadku rzeczy większych niż standardowe int / long / bigint
Andrew Backer
3
A jeśli chcesz, aby wielkie litery były printf "%X"
zapisywane
3
Aby wymusić wyjście takie jak „0x00”, możesz użyć printf „0x% 02X”
gbetous
1
... i bcnie jest dostępny wszędzie (przynajmniej nie w moim wbudowanym Linuksie).
Matthieu
69

Szesnastkowy na dziesiętny:

$ echo $((0xfee10000))
4276158464

Dziesiętny na szesnastkowy:

$ printf '%x\n' 26
1a
pjhobbs
źródło
15
bash-4.2$ printf '%x\n' 4294967295
ffffffff

bash-4.2$ printf -v hex '%x' 4294967295
bash-4.2$ echo $hex
ffffffff
Orwellophile
źródło
1
-v VARjest rozszerzeniem bash. Niewymienione na stronie podręcznika , ujawniane tylko wtedy, gdy dzwoni się printfbez argumentów
Adrian W
5

Przepraszam, moja wina, spróbuj tego ...

#!/bin/bash
:

declare -r HEX_DIGITS="0123456789ABCDEF"

dec_value=$1
hex_value=""

until [ $dec_value == 0 ]; do

    rem_value=$((dec_value % 16))
    dec_value=$((dec_value / 16))

    hex_digit=${HEX_DIGITS:$rem_value:1}

    hex_value="${hex_digit}${hex_value}"

done

echo -e "${hex_value}"

Przykład:

$ ./dtoh 1024
400
pjhobbs
źródło
1
Dzięki temu bardzo pomogło środowisku env. gdzie printfi hexpolecenia nie są dostępne.
benchuk
2
@benchuk, gdzie printfnie jest dostępne?
Matthieu
4

Próbować:

printf "%X\n" ${MY_NUMBER}
Rob Wells
źródło
2

W moim przypadku natknąłem się na jeden problem z użyciem rozwiązania printf:

$ printf "%x" 008 bash: printf: 008: invalid octal number

Najłatwiej było użyć rozwiązania z bc , sugerowanego w poście wyżej:

$ bc <<< "obase=16; 008" 8

Daniel Jeznach
źródło
Co Twoje rozwiązanie wnosi do tych napisanych przed laty?
Matthieu
1
@Matthieu Wspomina o problemie liczb z zerami wiodącymi, które Bash printf niepomocnie interpretuje jako ósemkowe, i demonstruje rozwiązanie, które pozwala uniknąć problemu.
mwfearnley
2
xd() {
    printf "hex> "
    while read i
    do
        printf "dec  $(( 0x${i} ))\n\nhex> "
    done
}
dx() {
    printf "dec> "
    while read i
    do
        printf 'hex  %x\n\ndec> ' $i
    done
}
sjas
źródło
1
# number conversion.

while `test $ans='y'`
do
    echo "Menu"
    echo "1.Decimal to Hexadecimal"
    echo "2.Decimal to Octal"
    echo "3.Hexadecimal to Binary"
    echo "4.Octal to Binary"
    echo "5.Hexadecimal to  Octal"
    echo "6.Octal to Hexadecimal"
    echo "7.Exit"

    read choice
    case $choice in

        1) echo "Enter the decimal no."
           read n
           hex=`echo "ibase=10;obase=16;$n"|bc`
           echo "The hexadecimal no. is $hex"
           ;;

        2) echo "Enter the decimal no."
           read n
           oct=`echo "ibase=10;obase=8;$n"|bc`
           echo "The octal no. is $oct"
           ;;

        3) echo "Enter the hexadecimal no."
           read n
           binary=`echo "ibase=16;obase=2;$n"|bc`
           echo "The binary no. is $binary"
           ;;

        4) echo "Enter the octal no."
           read n
           binary=`echo "ibase=8;obase=2;$n"|bc`
           echo "The binary no. is $binary"
           ;;

        5) echo "Enter the hexadecimal no."
           read n
           oct=`echo "ibase=16;obase=8;$n"|bc`
           echo "The octal no. is $oct"
           ;;

        6) echo "Enter the octal no."
           read n
           hex=`echo "ibase=8;obase=16;$n"|bc`
           echo "The hexadecimal no. is $hex"
           ;;

        7) exit 
        ;;
        *) echo "invalid no." 
        ;;

    esac
done
amol s. patil
źródło
1

To nie jest skrypt powłoki, ale jest to narzędzie CLI, którego używam do konwersji liczb między bin / oct / dec / hex:

    #!/usr/bin/perl

    if (@ARGV < 2) {
      printf("Convert numbers among bin/oct/dec/hex\n");
      printf("\nUsage: base b/o/d/x num num2 ... \n");
      exit;
    }

    for ($i=1; $i<@ARGV; $i++) {
      if ($ARGV[0] eq "b") {
                    $num = oct("0b$ARGV[$i]");
      } elsif ($ARGV[0] eq "o") {
                    $num = oct($ARGV[$i]);
      } elsif ($ARGV[0] eq "d") {
                    $num = $ARGV[$i];
      } elsif ($ARGV[0] eq "h") {
                    $num = hex($ARGV[$i]);
      } else {
                    printf("Usage: base b/o/d/x num num2 ... \n");
                    exit;
      }
      printf("0x%x = 0d%d = 0%o = 0b%b\n", $num, $num, $num, $num);
    }
CodyChan
źródło