I am currently looking for an alternative to the following code that works a little less 'wonky'.

printf "Please enter the ticket number:\t"; read vTICKET; vTICKET=$(printf %04d "$vTICKET"); printf "$vTICKET\n";

If I input 072 as the input, this is what I see

Please enter the ticket number: 072

I am wondering if there is another way I can be a little more forgiving on the input or with the read command? printf seemed like the cool way to add leading zeroes without actually testing string length.

New contributor
Michael is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

The leading zeros on the input value are causing the shell to interpret it as an octal number.

You can force decimal conversion using 10# e.g.

$ printf "Please enter the ticket number:\t"; read vTICKET; vTICKET=$(printf %04d "$((10#$vTICKET))" ); printf "$vTICKET\n";
Please enter the ticket number: 072

Note that in bash, you can assign the results of a printf to a variable directly using -v e.g. printf -v vTICKET %04d "$((10#$vTICKET))"

See also How do I stop Bash from interpreting octal code instead of integer?

  • Do we even need %04d and the accompanying interpretation? Wouldn't %04s be enough? – muru Jun 12 at 10:03
  • @muru hmm - is zero-padding supported for non-numeric conversion specifiers? I couldn't get that to work for me (bash 4.4.19) – steeldriver Jun 12 at 23:18
  • Ah, it's not portable. On macOS (presumably other BSDs), it works. Seems to based on what printf(3) does. Compiling a C file with printf("%04s", "072");, I get a warning from clang (nothing from GCC 9): flag '0' results in undefined behavior with 's' conversion specifier [-Wformat], but it prints 0072 all the same. – muru Jun 13 at 1:48
  • @muru interesting... with both clang 6.0.0-1ubuntu2 and gcc 7.4.0-1ubuntu1~18.04, C printf appears to ignore the 0 and pad to the specified width with spaces – steeldriver Jun 13 at 1:59

In Bash, you can get rid of any prefixing zeros. After setting on extglob first:

$ shopt -s extglob

You can use *(0) after ## in parameter expansion:

$ read -r TICKET; printf "%.4d\n" "${TICKET##*(0)}"

Once finished, you can go back to normal with extglob:

$ shopt -u extglob

Now *(0) undergoes the basic pathname expansion again:

$ read -r TICKET; printf "%.4d\n" "${TICKET##*(0)}"
$ read -r TICKET; printf "%.4d\n" "${TICKET##*(0)}"
bash: printf: asdfasdf072: invalid number

Your Answer

Michael is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.