Добавление ведущих нулей к шестнадцатеричному числу в скрипте bash

Я работаю над проектом шины CAN и пытаюсь отправить сообщение, чтобы установить время и дату. Я выяснил, как сообщение должно быть отформатировано, взял дату/время и сохранил в переменных. Я отлично преобразовал их в шестнадцатеричный формат, но мне нужно добавить начальные 0, чтобы дополнить необходимое пространство, требуемое сообщением.

Я пробовал методы, найденные в Интернете, для сценария bash, но у меня есть проблема: 2019 год — это 7E3 в шестнадцатеричном формате. Мне нужно, чтобы это отображалось как 07E3. При использовании awk для добавления начальных нулей E3 интерпретируется как инженерная нотация *10^3 и, следовательно, печатается как 7000. Ниже приведен мой сценарий вместе с изображением, показывающим формат сообщения шины CAN. Любая помощь приветствуется.

#!/bin/bash

#Store Date/Time in Variables
Year=`date '+%Y'`
Month=`date '+%m'`
Day=`date '+%d'`
Hour=`date '+%H'`
Minute=`date '+%M'`
Second=`date '+%S'`

#Convert Date/Time to Hexadecimel
HexYear=`echo "ibase=10;obase=16;$Year"| bc | awk '{ printf("%04d\n", $1) }'`
HexMonth=`echo "ibase=10;obase=16;$Month"| bc | awk '{ printf("%02d\n", $1) }'`
HexDay=`echo "ibase=10;obase=16;$Day"| bc | awk '{ printf("%02d\n", $1) }'`
HexHour=`echo "ibase=10;obase=16;$Hour"| bc | awk '{ printf("%02d\n", $1) }'`
HexMinute=`echo "ibase=10;obase=16;$Minute"| bc | awk '{ printf("%02d\n", $1) }'`
HexSecond=`echo "ibase=10;obase=16;$Second"| bc | awk '{ printf("%02d\n", $1) }'`

echo "The following is Decimel > Hex"
echo "$Year > $HexYear"
echo "$Month > $HexMonth"
echo "$Day > $HexDay"
echo "$Hour > $HexHour"
echo "$Minute > $HexMinute"
echo "$Second > $HexSecond"

формат сообщения шины CAN


person JPToadstool    schedule 04.01.2019    source источник


Ответы (3)


Ответ в awk, как и в другом форматировании printf, будет %0X, например:

$ echo 2019 01 04 | awk '{ printf("%02X%02X%04X\n", $2, $3, $1) }'
010407E3

x для шестнадцатеричного числа, регистр цифр от A до F соответствует букве, а 0 для ведущих нулей, после чего вы можете указать желаемую ширину (например, дополнить четыре цифры ведущими нулями в верхнем регистре: %04X).

И если вам не нужен awk ни для чего другого (например, для обработки нескольких строк), просто используйте printf напрямую:

$ printf "%02X%02X%04X\n" `date '+%m %d %Y'`
010407E3
person Arkku    schedule 04.01.2019
comment
Спасибо, это помогло мне добраться туда. Упростил мой код до следующего: HexYear=$(printf %04X\n $Year) HexMonth=$(printf %02X\n $Month) - person JPToadstool; 05.01.2019

Все, что echo|bc|awk можно было бы свести к

$: HexYear=$( printf "%04X\n" $Year )
$: echo "$Year > $HexYear"
2019 > 07E3

X > x, так как не требуется, чтобы переменная объявлялась в верхнем регистре.

person Paul Hodges    schedule 04.01.2019
comment
Я пробовал этот подход, но получаю следующий ответ: ./DateSet.sh: строка 13: объявлять: -u: недопустимая опция объявлять: использование: объявлять [-afFirtx] [-p] [имя[=значение] ... ] Далее следует Decimel › Hex 2019 › 01 › 01 04 › 04 22 › 16 55 › 37 35 › 23 - person JPToadstool; 05.01.2019
comment
Извините, не знаю, почему это неправильно отформатировано. Это напечатано как 2019 › ____ (просто пробел). Не уверен, почему. Ваш и ответ ниже помогли решить эту проблему, спасибо. - person JPToadstool; 05.01.2019
comment
Отредактировано - пропущено объявление переменной в верхнем регистре в пользу использования X вместо x. Извините, что у вас возникли проблемы, и добро пожаловать. - person Paul Hodges; 07.01.2019

Вы должны понимать, насколько неэффективно вызывать date 6 раз, когда вы можете вызвать его один раз, а затем вызвать bc + awk, чтобы сделать что-то, что awk может сделать в одиночку, а затем сделать ЭТО 6 раз. Найдите секунду, чтобы действительно подумайте о том, что делает ваш скрипт.

Посмотрите на это с date плюс любой awk:

$ awk -v dec="$(date '+%Y %m %d %H %M %S')" 'BEGIN {
    split(dec,a)
    hex = sprintf("%X %X %X %X %X %X",a[1],a[2],a[3],a[4],a[5],a[5])
    print dec, "->", hex
}'
2019 01 05 08 22 06 -> 7E3 1 5 8 16 16

или с помощью GNU awk для функций времени:

$ awk 'BEGIN {
    dec = strftime("%Y %m %d %H %M %S") 
    split(dec,a)
    hex = sprintf("%X %X %X %X %X %X",a[1],a[2],a[3],a[4],a[5],a[5])
    print dec, "->", hex
}'
2019 01 05 08 18 54 -> 7E3 1 5 8 12 12

и чтобы вернуть результат в оболочку:

$ hex=( $(awk 'BEGIN{dec=strftime("%Y %m %d %H %M %S"); split(dec,a); hex=sprintf("%X %X %X %X %X %X",a[1],a[2],a[3],a[4],a[5],a[5]); print hex}') )
$ declare -p hex
declare -a hex=([0]="7E3" [1]="1" [2]="5" [3]="8" [4]="1F" [5]="1F")
person Ed Morton    schedule 05.01.2019
comment
Спасибо за совет. На данный момент не беспокоюсь о неэффективности, так как я просто проверяю теории, чтобы убедиться, что они верны. Проект будет написан либо на питоне, либо на С, это только мои первые шаги в тестировании. - person JPToadstool; 06.01.2019
comment
Вызов даты 6 раз и т. д. сразу делает меня (человека) очевидным, что пытается сделать код. Люди тоже должны читать код, а (человеко-часы) стоят намного дороже, чем часы процессора. - person user187557; 14.05.2020