1

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?

2
  • 08 is considered octal Commented Nov 7, 2021 at 0:05
  • 1
    For your convenience, ShellCheck automatically says "i is an array value, not a key. Use directly or loop over keys instead.", "This loops over values. To loop over keys, use "${!array[@]}" (more) Commented Nov 7, 2021 at 0:38

4 Answers 4

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

looks like i do not need array for this at all!
Probably not. It depends what you're trying to do. There's also: printf '%s\n' {00..23} to just to print the hours as a list.
2

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 "%02d" $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.

Comments

1

You can specify it's 10-based :

echo ${hr[10#$i]}

1 Comment

very nice! # let b=10#0000000000009 , # echo "$b"
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.