Поменять местами шестнадцатеричное число в bash

10

Есть ли простая команда для изменения шестнадцатеричного числа?

Например, учитывая шестнадцатеричное число:

030201

Выход должен быть:

010203

Используя revкоманду, я получаю следующее:

102030

Обновить

$ bash --version | head -n1
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
$ xxd -version
xxd V1.10 27oct98 by Juergen Weigert
$ rev --version
rev from util-linux 2.20.1
Иньяки Мурильо
источник
2
Пожалуйста, не добавляйте ответ на свой вопрос.
кот
@cat Я добавил ответ, потому что тот, который работал для меня, находится в комментариях к выбранному ответу. Но я в порядке, удаляя это.
Иньяки Мурильо
2
Вы можете добавить его в качестве ответа, нажав кнопку «Ответить на этот вопрос» под полем для ответов (самостоятельные ответы приветствуются), и вы должны просто не ставить его в вопросе.
кот
2
Программист C во мне хочет сказать, что "010203" - это восьмеричное число, а не шестнадцатеричное число (0x10203)
добавлено
@infixed Вы не ошиблись, но я хотел получить ответ, который рассматривается 010203как шестнадцатеричный, хотя я и не использую 0x
Иньяки Мурильо

Ответы:

10

Вы можете преобразовать его в двоичный файл , обратить байты , при желании удалить завершающие символы новой строки rev<2,24 и преобразовать обратно:

$ xxd -revert -plain <<< 030201 | LC_ALL=C rev | tr -d '\n' | xxd -plain
010203

С помощью

$ bash --version | head -n1
GNU bash, version 4.3.42(1)-release (x86_64-redhat-linux-gnu)
$ xxd -version
xxd V1.10 27oct98 by Juergen Weigert
$ rev --version
rev from util-linux 2.28.2

Это не работает, если строка содержит байт NUL, потому что revбудет обрезать вывод в этой точке.

l0b0
источник
2
Я получаю 0102030aвместо010203
Иньяки Мурильо
@ l0b0 и я тоже, получите0102030a
بارپابابا
2
@ IñakiMurillo в вашей revверсии 2.20.1; использовать этот xxd -revert -plain <<< '030201' | LC_ALL=C rev | tr -d '\n'| xxd -plain
формат
2
revдо версии 2.24есть новая строка ошибки. больше информации github.com/karelzak/util-linux/commit/…
بارپابابا
1
Это не работает, если шестнадцатеричная строка содержит байт NUL '00'.
Сильвен Леру
10

Если в вашей системе есть revкоманда.

hex=030201
new_hex=$(printf %s "$hex" | dd conv=swab 2> /dev/null | rev)

Если есть команда tacили tail -r:

new_hex=$(echo "$hex" | fold -w 2 | tac | paste -sd '\0' -)

С zsh:

setopt extendedglob
new_hex=${(j::)${(s::Oa)${hex//(#b)(?)(?)/$match[2]$match[1]}}}

(как в ddподходе: поменять пары символов, разбить на список отдельных символов ( s::), изменить порядок ( Oa) и объединить ( j::)).

POSIXly:

new_hex=$(
  awk '
    BEGIN {
      hex = ARGV[1]; l = length(hex)
      for (i = 1; i < l; i += 2)
        new_hex = substr(hex, i, 2) new_hex
      print new_hex
    }' "$hex"
)

Или

new_hex=$(echo "$hex" |
  sed -e 'G;:1' -e 's/\(..\)\(.*\n\)/\2\1/;t1' -e 's/.//')

С perl:

new_hex=$(perl -le 'print reverse(shift =~ /../g)' -- "$hex")
Стефан Шазелас
источник
3
Я собирался предложить perl -F'(..)' -lane 'print reverse(@F)':)
Sundeep
1
@ Сандип, хорошо. Я не знал, что можно так использовать -F. (Я вижу это описано в split()руководстве сейчас).
Стефан Шазелас
1
насколько я знаю, -Fэто в основном разделение на $_... кроме использования регулярных выражений, например, -F'/"\K\|(?=")/'можно также указать количество разделений ... например -F'/:/,$_,2'... использовать, ()если разделитель также должен быть захвачен
Sundeep
Вместо пасты вы можете использоватьtr -d '\n'
AKHolland
10

С fold+ tac+ tr:

$ echo 030201|fold -w2|tac|tr -d "\n"
010203
  • fold - разделить каждые 2 байта
  • tac - обратный кот
  • tr - удалить переводы строк
Ипор Сирсер
источник
4
perl -nE 'say reverse /(..)/g'

Это возвращает каждую шестнадцатеричную строку:

  • /(..)/g строит список с захваченными матчами
JJoao
источник
4

(для полноты картины)

$ echo 030201 | grep -o .. | tac | paste -sd '' -
010203
дирижабль
источник
1
Это работает, если байт NUL '00' находится на входе.
Сильвен Леру
0

На основании ответа Ипора Сирсера https://unix.stackexchange.com/a/321867/337458, я бы порекомендовал вам это, ~/.bashrcчтобы у вас была хорошая команда, которую вы можете просто вызвать:

function hex_inverse() {
    echo ${1} | fold -w2 | tac | tr -d "\n" ; echo "" 
}

$> hex_inverse 030201

010203
mschmoock
источник