Adding leading zeros to a Hex number within bash script

I'm working on a CAN bus project, and trying to send a message to set the time and date. I've worked out how the message needs to be formatted, grabbed the date/time and stored in variables. I've converted them to hex just fine, but I need to add leading 0s to pad to the required space required by the message.

I've tried methods seen online for a bash script, but I have a problem: The year 2019 is 7E3 in hex. I need this displayed as 07E3. When using awk to add the leading 0s, the E3 is being interpreted as Engineering notation *10^3, and therefore printing as 7000. My script is below, along with an image showing the CAN bus message format. Any help is appreciated.

#!/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 bus message format

The answer in awk, as in other printf formatting, is %0X, e.g.:

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

The x is for heXadecimal, case of the digits A-F matches that of the letter, and the 0 is for leading zeroes, after which you can specify the desired width (e.g., pad to four digits with leading zeroes in uppercase: %04X).

And if you don't need awk for anything else (such as to process multiple lines), just use printf directly:

$ printf "%02X%02X%04X\n" `date '+%m %d %Y'`
010407E3

Help needed in padding leading zeros, I need to pad each value with leading zeros such that total lenght of each value is 16. Example: cat tmp.txt 502455 Shell Programming & Scripting paddedData​=`printf "%s" $hex ` echo $paddedData results in 0 1 9. A i want 00 01 09. 0A LXer: Add leading zeroes that aren't really leading: LXer: Syndicated Linux News: 0: 09-13-2019 12:31 PM: Script is stripping off leading zero: wtaicken: Programming: 5: 11-12-2009 07:02 AM: Bash Maths Keeping leading zero's: lin*x: Linux - Newbie: 1: 08-05-2009 11:44 PM: In Python, printing leading zero for hex numbers 0 through f: donpar

All that echo|bc|awk could be boiled down to

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

X > x, as it doesn't require the var to be declared uppercased.

Integer with leading zeros (portable)?, In bash, there's no option to turn it off, but you can use the writing a POSIX portable script, in which case, you'd want to strip the leading zeros as you have shown. a decimal number printf '%d' "${sign}0x$hex" >/dev/null # for hex numbers The actual code for the loop has not been added for simplicity. I'm using the DEC2HEX function to convert decimal numbers in cells to hex numbers. For Hex 00 to 09, how do I format the cells so that there is a leading zero?

You must realize how immensely ineffecient it is to call date 6 times when you could call it once and then call bc + awk to do something awk could do alone and then do THAT 6 times as well. Take a second to really think about what your script is doing.

Look at this with date plus any 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

or with GNU awk for time functions:

$ 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

and to get the result back into shell:

$ 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")

How do I get 0-padded numbers in {} (brace expansion)?, Bash brace expansions could generate the numbers with leading zeros (since bash 4.0 alpha+ ~2009-02-20): $ echo {001..023} 001 002 '/Mem|Swap/{print \$4}')". Then, the whole script will look like this: Note that zero-padding for brace expansions was introduced in bash 4. – chepner Jan 5 '17 at 19:  Hi, Can anyone help me how to add leading zero's (0's) infront of numbers in unix script. For more details. x=450 Y=2344 i want the out put of 0000045 | The UNIX and Linux Forums

Numerical Constants, A shell script interprets a number as decimal (base 10), unless that number A number preceded by 0x is hexadecimal (base 16). Octal: numbers preceded by '0' (zero) let "oct = 032" echo "octal number = $oct" # 26 # Expresses result in 

Tcl Built-In Commands - format manual page, The return value from format is the formatted string. a minimum number of digits to print (leading zeroes will be added if necessary). the integer may either be in decimal, in octal (with a leading 0) or in hexadecimal (with a leading 0x).

Convert between hex and decimal | Vim Tips Wiki, This tip shows how to convert numbers from hexadecimal to decimal, and the reverse. you can enter, and some scripts to easily replace hex numbers with decimal, or to The first shows that adding zero to a string converts the string to a number. :echo printf('%04x', 1234), 04d2, same, with leading zeros to four digits.

Comments
  • Thank you, this helped me get there. Simplified my code to the following: HexYear=$( printf "%04X\n" $Year ) HexMonth=$( printf "%02X\n" $Month )
  • I tried that approach, but I get the following response: ./DateSet.sh: line 13: declare: -u: invalid option declare: usage: declare [-afFirtx] [-p] [name[=value] ...] The following is Decimel > Hex 2019 > 01 > 01 04 > 04 22 > 16 55 > 37 35 > 23
  • Sorry, not sure why this hasn't formatted correctly. This printed as 2019 > ____ (just blank space). Unsure as to why. Yours and the answer below helped solve this, thank you.
  • Edited - skipped the uppercased declaration of the var in favor of using X vs x. Sorry you had trouble, and you're welcome.
  • Thanks for the advice. Not worried about inefficiency at the moment, as this is just me testing theories to make sure they’re correct. The project will be either written in python or C, this is just my first steps in testing.
  • Calling date 6 times, etc., makes it immediately apparent to me (a human) what the code is trying to do. Humans have to read code too, and (hu)man-hours are far more expensive than CPU-hours.