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

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

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


person skiphoppy    schedule 18.12.2008    source источник
comment
Я должен спросить, а что плохого в printf? Многие распространенные языки программирования поддерживают форматирование, подобное printf, поэтому приведенные ниже решения printf наверняка будут самыми простыми для понимания разработчиками.   -  person Michael Scheper    schedule 29.11.2013
comment
Боже, не знаю - это было пять лет назад! Думаю, может, я думал, что это не настоящая оболочка или что-то в этом роде.   -  person skiphoppy    schedule 06.12.2013


Ответы (10)


echo "obase=16; 34" | bc

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

( echo "obase=16" ; cat file_of_integers ) | bc
person Bill Karwin    schedule 18.12.2008
comment
Я посмотрел на bc (1) и dc (1) и пропустил это. - person Keltia; 19.12.2008
comment
Есть ли способ превратить его в фильтр, который будет принимать произвольное количество целых чисел в одной строке? - person skiphoppy; 19.12.2008
comment
@skiphoppy: Если вы напишете: echo obase = 16; 12 34 56 | bc вы получите 1E240, точно так же, как если бы вы написали: echo obase = 16; 123456 | До нашей эры. Таким образом, способ работать с произвольным числом целых чисел в одной строке - это поместить каждое число в отдельную строку: tr '' '\ 015' ‹input | bc (отображать пробелы в символы новой строки). - person Jonathan Leffler; 25.12.2008
comment
Это замечательно, если у вас есть bc, но printf является частью самого bash. - person fuzzyTew; 12.07.2013
comment
@fuzzyTew, конечно, это правда. Но только если у вас есть bash. :-) - person Bill Karwin; 12.07.2013
comment
@Bill Karwin, или zsh, или busybox, но, может быть, это не какая-то оболочка, которую я не пробовал? Я больше не устанавливаю plain sh, но очевидно, что skiphoppy ищет другие варианты. - person fuzzyTew; 14.07.2013
comment
Мне нравится аспект трубопровода, но как сделать наоборот? От десятичного числа к шестнадцатеричному? - person Sridhar Sarnobat; 27.05.2015
comment
@ Sridhar-Sarnobat, это десятичное в шестнадцатеричное. Я полагаю, вы имеете в виду преобразовать шестнадцатеричный формат в десятичный. Для этого установите ibase=16. Вы можете прочитать руководство по bc для получения дополнительных сведений. . - person Bill Karwin; 28.05.2015
comment
вы хотите добавить, что bc чувствителен к регистру. то есть echo "ibase=16; dead" | bc не будет работать, нужно делать echo "ibase=16; DEAD" | bc, меня это немного удивило - person graywolf; 18.08.2016

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

printf "%x\n" 34
22

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

person Keltia    schedule 18.12.2008
comment
Отлично, мне нужно было преобразовать IPv4-адрес в IPv6, это работает! - person Lekensteyn; 19.02.2011
comment
У него не намного больше POSIX, чем у printf. Это работает даже в sh. - person Orwellophile; 12.05.2012
comment
printf не отличается высокой точностью. bc есть. например, принимая 238862874857408875879219909679752457540 в качестве входных данных, printf дает нам слишком большой результат. метод BC отлично подходит для вещей, больших, чем стандартный int / long / bigint - person Andrew Backer; 01.09.2014
comment
И, если вы хотите использовать прописные буквы в шестнадцатеричном формате, используйте printf "%X" с прописными буквами X. - person andrybak; 30.09.2015
comment
И для принудительного вывода типа 0x00 вы можете использовать printf 0x% 02X - person gbetous; 18.12.2017
comment
... и bc доступен не везде (по крайней мере, не в моем встроенном Linux). - person Matthieu; 17.08.2018
comment
И не забывайте -v VAR как в printf -v VAR "%x" 34 && echo $VAR - person Matthieu; 17.08.2018

Из шестнадцатеричного в десятичное:

$ echo $((0xfee10000))
4276158464

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

$ printf '%x\n' 26
1a
person pjhobbs    schedule 15.12.2009

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

#!/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
person pjhobbs    schedule 12.03.2010
comment
Спасибо, это очень помогло env. где команды printf и hex недоступны. - person benchuk; 04.01.2015
comment
@benchuk где printf недоступен? - person Matthieu; 17.08.2018

Пытаться:

printf "%X\n" ${MY_NUMBER}
person Rob Wells    schedule 18.12.2008
comment
В чем разница между $MY_NUMBER и ${MY_NUMBER}? - person SasQ; 05.09.2020
comment
@SasQ с использованием скобок принудительно интерпретирует символ, который вы намеревались использовать, то есть просто MY_NUMBER. Использование скобок позволяет вам делать такие вещи, как $ {MY_TEXT_FRAG _ $ {MY_NUMBER}} для объединения имен переменных. - person Rob Wells; 07.09.2020

В zsh вы можете делать такие вещи:

% typeset -i 16 y
% print $(( [#8] x = 32, y = 32 ))
8#40
% print $x $y
8#40 16#20
% setopt c_bases
% print $y
0x20

Пример взят со страницы zsh docs, посвященной арифметической оценке.

Я считаю, что у Bash есть аналогичные возможности.

person Alastair    schedule 18.12.2008

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

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

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

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

person Daniel Jeznach    schedule 09.02.2016
comment
Что ваше решение добавляет к решениям, написанным годами ранее? - person Matthieu; 17.08.2018
comment
@Matthieu В нем упоминается проблема чисел с ведущими нулями, которые Bash printf бесполезно интерпретирует как восьмеричные, и демонстрирует решение, позволяющее избежать этой проблемы. - person mwfearnley; 21.10.2019

Это не сценарий оболочки, но это инструмент 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);
    }
person CodyChan    schedule 23.08.2018

Вау, я не знал, что printf доступен в оболочке!

С учетом сказанного, я удивлен, что никто не прокомментировал размещение printf в сценарии оболочки (который затем вы можете поместить в свой личный каталог bin, если хотите).

echo printf 0x% x \ n $ 1 ›шестнадцатеричный chmod + x шестнадцатеричный

Теперь просто запустите: ./hex 123

Возвращает: 0x7b

person Aaron Volz    schedule 24.03.2021

person    schedule
comment
-v VAR - это расширение bash. Не упоминается на странице руководства, отображается только при вызове printf без аргументов - person Adrian W; 24.10.2018
comment
@AdrianW это в руководстве: gnu.org/software/bash /manual/bash.html#Bash-Builtins - person Roland; 20.07.2021