Home > Software engineering >  How to create an array with leading zeros in Bash?
How to create an array with leading zeros in Bash?

Time:11-07

Not very difficult:

#!/bin/bash

hr=(00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23)

for i in ${hr[@]}; do
echo ${hr[i]}
done

But:

user@userver:$ ./stat.sh
00
01
02
03
04
05
06
07
./stat.sh: string 7: 08: value too great for base (error token is "08")

Bash thinks that leading zero means octal number system. What to do?

CodePudding user response:

I think your fundamental problem is that you're using each element of the array to index the array itself.

If you want to just print out the array elements, you should be outputting ${i} rather than ${hr[i]}. The latter is useless in your current code since element zero is 00, element one is 01, and so on.

On the chance that this is a simplified example and you do want to reference a different array based on the content of this one, you have a couple of options:

  • Realise that the value of an integer and the presentation of it are two distinct things. In other words, use 0, 1, 2, ... but something like printf "d" $i if you need to output it (noting this is only ouputting the value in the first array, not the one you're looking up things in).
  • Exclusively use strings and a string-based associative array rather than an integer-based one, see typeset -A for detail.

CodePudding user response:

When you iterate with:

for i in ${hr[@]}; do

It is iterating the values of the array witch are: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23

But when within the loop it has:

echo ${hr[i]}

it is using i as the index of the hr array.

In Bash, an index within the brackets of an array like [i] is an arithmetic context. It means while the value of i=08 the leading 0 within the arithmetic context causes the number to be treated as an octal number, and 8 is an invalid octal number.

If you wanted to iterate your array indexes to process its values by index, then you'd start the loop as:

for i in "${!hr[@]}"; do

This one will perfectly work as it iterates the index into the variable i :

#!/usr/bin/env bash

declare -a hr=(00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23)

for i in "${!hr[@]}"; do
printf '%s\n' "${hr[i]}"
done

Now if all you want is iterate the values of the hr array, just do this way:

#!/usr/bin/env bash

declare -a hr=(00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23)

for e in "${hr[@]}"; do
printf '%s\n' "$e"
done

No need to index the array within the loop, since the elements are already expanded into e.

CodePudding user response:

You can specify it's 10-based :

echo ${hr[10#$i]}

CodePudding user response:

one way is .... `$a=(echo {0..0}{1..99}) $ echo ${a[@]} echo 01 02 03 04 05 06 07 08 09 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099

CodePudding user response:

Use brace expansion (ranges, repetition).

To create an array:

hours=({00..23})

Loop through it:

for i in "${hours[@]}"; do
    echo "$i"
done

Or loop through a brace expansion:

for i in {00..23}; do
    echo "$i"
done

Regarding your error, it's because in bash arithmetic, all numbers with leading zeroes are treated as octals, and 08 and 09 are invalid octal numbers. All indexed array subscripts are evaluated as arithmetic expressions. You can fix the problem by using the notation base#number to specify a number system. So for base 10: 10#09, or for i=09, 10#$i. The variable must be prefixed with $, 10#i does not work.

You should be printing your array like this anyway:

Loop through elements:

for i in "${hr[@]}"; do
    echo "$i"
done

Loop through indexes:

for i in "${!hr[@]}"; do
    echo "index is $i"
    echo "element is ${hr[i]}"
done

If you need to do arithmetic on the hours, or any zero padded number, you will lose the zero padding. You can print it again with printf: printf %.2d "$num", where 2 is the minimum width.

  • Related