Преобразование десятичного числа в шестнадцатеричное в сценарии оболочки UNIX


110

Что я могу использовать в сценарии оболочки UNIX для преобразования десятичных чисел в шестнадцатеричные? Я думал, что od сделает трюк, но он не понимает, что кормлю его ASCII-представлениями чисел.

printf? Валовой! Используете это сейчас, но что еще доступно?


8
Я должен спросить, а что плохого в printf? Многие распространенные языки программирования поддерживают форматирование, подобное printf, поэтому приведенные ниже решения printf наверняка будут самыми простыми для понимания разработчиками.
Майкл Шепер

4
Боже, не знаю - это было пять лет назад! Думаю, может, я думал, что это не настоящая оболочка или что-то в этом роде.
skiphoppy 06

Ответы:


108
echo "obase=16; 34" | bc

Если вы хотите отфильтровать целый файл целых чисел, по одному в строке:

( echo "obase=16" ; cat file_of_integers ) | bc

1
Я посмотрел и на bc (1), и на dc (1) и пропустил это.
Keltia

3
@skiphoppy: Если вы напишете: echo "obase = 16; 12 34 56" | bc вы получите 1E240, точно так же, как если бы вы написали: echo "obase = 16; 123456" | До нашей эры. Таким образом, способ работать с произвольным числом целых чисел в одной строке - это поместить каждое число в отдельную строку: tr '' '\ 015' <input | bc (отображать пробелы в символы новой строки).
Джонатан Леффлер,

1
Это замечательно, если у вас есть bc, но printf является частью самого bash
fuzzyTew

1
@Bill Karwin, или zsh, или busybox, но, может быть, это не какая-то оболочка, которую я не пробовал? Я больше не устанавливаю plain sh, но очевидно, что skiphoppy ищет, какие еще есть варианты
fuzzyTew

2
@ Шридхара-Sarnobat, это является десятичной в шестнадцатеричную. Я полагаю, вы имеете в виду преобразовать шестнадцатеричный формат в десятичный. Для этого установите ibase=16. Вы можете прочитать руководство по bc для получения более подробной информации.
Билл Карвин

186

Пробовали printf(1)?

printf "%x\n" 34
22

Вероятно, есть способы сделать это с помощью встроенных функций во всех оболочках, но это будет менее переносимо. Я не проверял спецификации POSIX sh, чтобы узнать, есть ли у него такие возможности.


5
У него не намного больше POSIX, чем у printf. Это работает даже в «ш».
Orwellophile

4
printf не отличается высокой точностью. bcявляется. например, принимая в 238862874857408875879219909679752457540качестве входных данных, printf дает нам «слишком большой результат». метод BC отлично подходит для вещей, больших, чем стандартный int / long / bigint
Эндрю Бэкер

3
И, если вы хотите использовать прописные буквы в шестнадцатеричном printf "%X"
формате

3
И для принудительного вывода типа «0x00» вы можете использовать printf «0x% 02X»
gbetous

1
... и bcдоступен не везде (по крайней мере, не в моем встроенном Linux).
Матье

69

Шестнадцатеричное в десятичное:

$ echo $((0xfee10000))
4276158464

Десятичное в шестнадцатеричное:

$ printf '%x\n' 26
1a

15
bash-4.2$ printf '%x\n' 4294967295
ffffffff

bash-4.2$ printf -v hex '%x' 4294967295
bash-4.2$ echo $hex
ffffffff

1
-v VARэто расширение bash. Не упоминается на странице руководства , раскрывается только при вызове printfбез аргументов
Adrian W

5

Извините за мою ошибку, попробуйте это ...

#!/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}"

Пример:

$ ./dtoh 1024
400

1
Спасибо, это очень помогло env. где printfи hexкоманды недоступны.
Benchuk

2
@benchuk где printfнедоступен?
Matthieu



2

В моем случае я наткнулся на одну проблему с использованием решения printf:

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

Самый простой способ - использовать решение с bc , предложенное в посте выше:

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


Что ваше решение добавляет к решениям, написанным годами ранее?
Matthieu

1
@Matthieu В нем упоминается проблема чисел с ведущими нулями, которые Bash printf бесполезно интерпретирует как восьмеричные, и демонстрирует решение, позволяющее избежать этой проблемы.
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
}

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

1

Это не сценарий оболочки, но это инструмент cli, который я использую для преобразования чисел между 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);
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.