13

Note: I am NOT asking this question

I looked for information on how to loop over a range of discontiguous numbers such as 0,1,2,4,5,6,7,9,11 without having to put the numbers in by hand and still use the ranges.

The obvious way would be to do this:

for i in 0 1 2 4 5 6 7 9 11; do echo $i; done
Community
  • 1
  • 1
MrMas
  • 1,143
  • 2
  • 14
  • 28
  • 1
    My question is: where did these arbitrary sub-ranges come from in the first place? – Barmar Aug 08 '14 at 01:14
  • Barmar -- suppose I want to run something with ssh on multiple machines. When they were initially installed, IT installed them in a one-up fashion. Then a few of them were re-purposed. Now I need to loop over a *discontiguous* list of numbers. – MrMas Aug 08 '14 at 16:06
  • And you don't have a list of them in a file somewhere, you have to hard-code it into each script that wants to do something with them? – Barmar Aug 08 '14 at 16:17
  • Which means that the next time one of them is repurposed or you add new machines, you'll need to update all the scripts that contain this `for` loop. Do yourself a favor and make a file. – Barmar Aug 08 '14 at 16:18
  • I just work here. ;-) – MrMas Aug 08 '14 at 18:23
  • @Barmar there are other reasons why you might want to use discontinuous numbers. For example, file names having some numerical suffix that is meaningful and distinguishes them from the other files with the same stem. So I think that it is a valid question. – Lynsey Jul 12 '17 at 13:55
  • @LynseyHall I maintain my original position: if there's no rule to generate the number, then they're arbitrary and probably should be listed in a file or database. The only thing the accepted answer does is save a few characters (and not even that -- `{0..2}` is 1 more character than `0 1 2`). – Barmar Jul 12 '17 at 15:56
  • @Barmar There are many reasons to use a disjointed numeric sequence that are single-use and so do not merit the overhead of a file or a database. And so I find your solution useful on a regular basis (just used it again for a completely different situation yesterday). – MrMas Jul 13 '17 at 22:40

4 Answers4

31
for i in {0..2} {4..6} {7..11..2}; do echo $i; done

See the documentation of bash Brace Expansion.

Barmar
  • 741,623
  • 53
  • 500
  • 612
4

Edit: oops, didn't realise there were missing numbers.

Updated: Define ranges and then use a while loop for each range. e.g.

ranges="0-2 4-7 9 11"
for range in $ranges
do
    min=${range%-*}
    max=${range#*-}
    i=$min
    while [ $i -le $max ]
    do
        echo $i
        i=$(( $i + 1 ))
    done
done

http://ideone.com/T80tfB

Sodved
  • 8,428
  • 2
  • 31
  • 43
4

As others have noted, brace expansion provides a way to select ranges, but you can also assign the results of multiple brace expansions to a variable using echo {..} {..}. This may cut down on the typing in the body of the for loop:

#!/bin/bash

range="`echo {2..6} {31..35} {50..100..10}`"

for i in $range; do echo $i; done

exit 0

output:

2
3
4
5
6
31
32
33
34
35
50
60
70
80
90
100
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
2
for i in `cat file.txt`; do echo $i; done

where file.txt contains:

0
1
2
4
5
6
7
9
11
William
  • 2,695
  • 1
  • 21
  • 33
  • I didn't say this explicitly in my question, but the point of iterating over something BESIDES a list of numbers would be to save work. up-vote for sheer cheek. – MrMas Aug 08 '14 at 01:12
  • 1
    for those who decided to use this approach, please note it is ` not ' around the cat command – Y00 Sep 04 '21 at 04:37