BASH базовое преобразование из десятичного в шестнадцатеричное

29

В Bash, как сделать преобразование базы из десятичной в другую, особенно в шестнадцатеричную. Кажется, легко пойти другим путем:

$ echo $((16#55))
85

С помощью веб-поиска я нашел скрипт, который выполняет математические и символьные манипуляции для преобразования, и я мог бы использовать это как функцию, но я бы подумал, что bash уже имеет встроенное базовое преобразование - Является ли?

Дейв Роув
источник
stackoverflow.com/questions/378829/…
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

Ответы:

35

С помощью bash(или любой оболочки при условии, что printfкоманда доступна (стандартная команда POSIX, часто встроенная в оболочки)):

printf '%x\n' 85

С помощью zshвы также можете сделать:

dec=85
hex=$(([##16]dec))

Это работает для баз от 2 до 36 (с 0-9a-zучетом регистра без учета цифр).

С помощью ksh93вы можете использовать:

dec=85
base54=$(printf %..54 "$dec")

Который работает для баз от 2 до 64 (с 0-9a-zA-Z@_цифрами).

С kshи zshесть также:

$ typeset -i34 x=123; echo "$x"
34#3l

Хотя это ограничено основами до 36 в ksh88, zsh и pdksh и 64 в ksh93.

Обратите внимание, что все они ограничены размером longцелых чисел в вашей системе ( intс некоторыми оболочками). Для чего-то большего, вы можете использовать bcили dc.

$ echo 'obase=16; 9999999999999999999999' | bc
21E19E0C9BAB23FFFFF
$ echo '16o 9999999999999999999999 p' | dc
21E19E0C9BAB23FFFFF

При поддерживаемых базах в диапазоне от 2 до некоторого числа POSIX должно быть не менее 99. Для баз, превышающих 16, цифры больше 9 представляются в виде разделенных пробелами 0-запятых десятичных чисел.

$ echo 'obase=30; 123456' | bc
 04 17 05 06

Или то же самое с dc( bcраньше было (и до сих пор есть в некоторых системах) оболочкой dc):

$ echo 30o123456p | dc
 04 17 05 06
Стефан Шазелас
источник
Спасибо. Именно то, что я искал. (И смущающе просто.)
Дейв Роув
Что если вы хотите создать произвольную базу, которую вы можете указать с помощью #?
flarn2006
@ flarn2006. С bashвстроенных команд, вы можете ввода чисел в любой системе счисления, но не выводится в любом основании, кроме 8, 10 и 16. Для других баз, вам потребуется еще один снаряд , как zshили kshили использование bc/dc.
Стефан Шазелас
1
@ StéphaneChazelas Правда? Это немного странно. Кажется, что они были слишком ленивы, чтобы программировать синтаксис для этого или что-то; ни в коем случае идея вывода в любой базе не пришла бы им в голову, если бы они реализовали ввод.
flarn2006
alias hex="printf '%x\n'"
mwfearnley
5

Используйте printf:

$ printf "%d %x\n" $((16#55)) $((10#85))
85 55

Чтобы присвоить значение переменной, используйте подстановку команд:

$ x=$( printf "%x" 85 ) ; echo $x
55
Janis
источник
4
Или используйте -vопцию для встроенного printf:printf -v foo "%d" $((16#BEEF)); echo $foo
Гленн Джекман
@Glenn Использование нестандартных опций (вроде -v) здесь не нужно; Я бы избежал этого.
Янис
3
-vбудет избегать форка и трубы (в bash, а не в ksh93, который не будет форкнуть здесь, как printfвстроено). Обратите внимание, что $((16#55))это не является стандартным.
Стефан Шазелас
@ StéphaneChazelas, подожди минутку. Вы говорите, что ksh93 не форк для x=$(some_builtin)?
Гленн Джекман
1
@glennjackman, да, это только вилки для выполнения внешних команд.
Стефан Шазелас
2

Используйте встроенную замену Arithmetic Expansion, присутствующую во всех POSIX-совместимых оболочках, что в наши дни является довольно универсальным.

$ echo $((0xbc))
188

а также

$ hex=dead
$ dec=$((0x$hex))
$ echo $dec
57005

ВНИМАНИЕ: В частности, в последнем примере расширение может привести к непредвиденным результатам - шестнадцатеричные цифры в переменной «hex» должны образовывать допустимую шестнадцатеричную константу, в противном случае могут появиться потенциально неясные сообщения об ошибках. например, если 'hex' было '0xdead', арифметическое расширение стало бы 0x0xdead, что не интерпретируется как константа. Конечно, в этом случае арифметическое расширение $ (($ hex)) сделает свое дело. Читателю оставлено в качестве упражнения создание простого сопоставления с шаблоном обработки подстроки, которое бы удалило необязательный префикс «0x».

Марк ван дер Пол
источник
4
Вы делаете то же самое, что и ОП в его примере; он ищет обратную операцию.
Томас Гайот-Сионнест
0

Вы можете использовать библиотеку awk Velor :

$ velour -n 'print n_baseconv(15, 10, 16)'
F

Или:

$ velour -n 'print n_baseconv(ARGV[1], 10, 16)' 15
F
Стивен Пенни
источник