1. Introduction
When scripting or formatting command arguments, we may want to transform numbers. One such transformation is the so-called zero padding. In essence, padding with zeroes results in a fixed-length number with as many zero prefixes or fractional suffixes as needed. For example, when padding to five (5) characters, 666 would become 00666, while 66600 would remain unchanged.
In this tutorial, we explore standard methods to pad a number with zeroes in the Linux shell. First, we use a shell built-in. Next, a tool available on the majority of Linux systems takes the spotlight. Finally, we discuss standardized ways to remove zero prefixes and suffixes.
Notably, although the same can be achieved with third-party tools such as interpreters like Perl and Python, we only explore solutions available in standard Linux environments and shells.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.
2. Zero Padding With Bash printf
Since the name of the printf Bash builtin means print formatted, it’s the de facto way to format different data types for printing.
2.1. Integer
First, let’s output a regular decimal integer with the %d format specifier:
$ printf '%d' 666
666
Now, we can pad our number to eight characters:
$ printf '%08d' 666
00000666
By adding a 0 after the % percent sign, we request zero padding. The number (8) between 0 and the format specifier d designates the desired total number length.
2.2. Floating Point
In fact, we can perform padding with a floating point number as well:
$ printf '%010.5f' 666.0666
0666.06660
Let’s decode the format string:
- % – format specifier start
- 0 – zero padding
- 10 – total result length (with decimal point)
- . – fraction format specifier start
- 5 – fraction length with postfix zero padding
- f – floating point format
Notably, we get 10 characters in total, but one of them is the decimal point. Further, zero padding is postfixed for the fractional part.
2.3. Zero Prefixes
In fact, there is an important pitfall to zero padding when using printf:
$ printf '%d' 0666
438
Critically, prefixing the actual number with 0 beforehand would result in printf interpreting it as an octal. Later, we’ll explore ways to avoid such situations.
3. Zero Padding With awk
awk‘s built-in printf statement enables us to output data in the required format:
$ awk 'BEGIN { printf "%05d\n", "666" }'
00666
Of course, we can use shell variables in awk:
$ num=666
$ awk -v input="$num" 'BEGIN{ printf "%05d\n", input }'
00666
The format string of awk printf adheres to the same rules as that of Bash.
4. Removing Zero Padding
In general, there are several methods to remove zero padding and avoid issues with it when using printf.
In our examples, we either use a literal number or the one within the $num variable:
$ num=0666
$ echo "$num"
0666
Let’s see how we can remove the padding.
4.1. Loop
Initially, we can remove all 0 prefixes with a shell loop:
$ while [ "$num" != "${num#0}" ]; do num=${num#0}; done
If we know we have a floating point number, using ${num%0} with the same syntax would also remove 0 suffixes.
Even better, this method uses standard POSIX parameter expansion, so it’s highly portable.
4.2. Using awk
The standard awk utility provides at least four ways to remove zero-padding:
- sub() function with regular expressions (regex)
- int() function
- Through simple arithmetic calculations
- printf statement
Let’s see the sub() regex awk solution first:
$ echo "0666" | awk '{sub(/^0*/,"")}1'
666
In this case, we match as many zeroes as possible with the * wildcard after 0 from the ^ beginning of the string. Next, we replace them with an “” empty string. After that, we use a print shortcut (1) after the } closing curly bracket.
Alternatively, for integers, we can simply do a conversion with int() and perform the same print:
$ echo "0666" | awk '{$0=int($0)}1'
666
When we perform arithmetic operations such as +, -, *, /, on a string, awk implicitly converts the string to a number. Therefore, we can make use of this feature to remove the leading zeros. Let’s see some examples:
$ awk '{$0=$0+0}1' <<< "0666"
666
$ awk '{$0=$0*1}1' <<< "0666"
666
$ awk '{$0=$0-0}1' <<< "0666"
666
It’s worth mentioning that we used “here string” instead of “echo and pipe” in the examples above to provide input to awk. The advantage is we don’t need an extra process to feed awk input data.
Finally, we can employ the printf statement of awk just like printf in Bash:
$ awk '{printf "%08d\n",$0;}' <<< "0666"
00000666
Now, let’s use one more standard POSIX tool.
4.3. Using sed
Another way to remove 0 affixes uses sed:
$ echo "$num" | sed 's/^0*//'
666
Here, we employ a sed regular expression to match zero or more 0 characters at the ^ beginning of the string. Then, just like with awk, we [s]ubstitute them with an // empty string.
In the case of floating point number suffix padding, we can use a similar regular expression:
$ echo 6660.066600 | sed 's/0*$//'
6660.0666
This time, we remove relative to the $ end of the number string.
5. Summary
In this article, we looked at ways to add and remove zero padding in a standard POSIX environment.
In conclusion, many vanilla shells, including Bash, provide the necessary utilities for prepending, appending, and removing zeroes from numbers.