my recent reads..

Atomic Accidents: A History of Nuclear Meltdowns and Disasters; From the Ozark Mountains to Fukushima
Power Sources and Supplies: World Class Designs
Red Storm Rising
Locked On
Analog Circuits Cookbook
The Teeth Of The Tiger
Sharpe's Gold
Without Remorse
Practical Oscillator Handbook
Red Rabbit

Monday, January 29, 2007

Handling range parameters in Bash

I've come across a few occasions where I wanted to specify a "range parameter" for Bash scripts. Like "1..4" meaning do for 1,2,3 and 4.

Here's a simple trick that uses the (relatively obscure) variable expansion and substring replacement capabilities of the shell.
#!/bin/bash
v_range="1..3" # or you could have taken it as a script parameter
v_start=${v_range%%.*} # chomp everything from the left-most matching "."
v_end=${v_range##*.} # chomp everything up to the right-most matching "."

The repeated %% and ## basically mean you will get a "greedy" match, so you can say "1..4" or "1....5"; it doesn't matter how many repeats you have of the range delimiter. Of course, you can choose other delimiters such as a hyphen, as in "5-10", if you wish.

Now that you have extracted the start and end indices, you can then loop or whatever to your hearts content:
for ((a=v_start; a <= v_end ; a++))
do
echo "Looping with a=$a"
done

For more information on variable expansion, see 9.3 in the Advanced Bash Scripting Guide.

Postscript 5-Feb-2008:
We live and learn! Hat tip to buford for alerting me to the seq utility, which simplifies the iteration over a range, as in:
for a in `seq 1 10`
do
echo "Looping with a=$a"
done

You still need to determine the start and end values of the range, which is the whole point of the variable expansions approach posted here.

9 comments:

Anonymous said...

for f in `seq 1 10`; do echo $f; done

Anonymous said...

It's not a builtin, it's a program:
type seq:
seq is hashed (/usr/bin/seq)

It's part of coreutils.

Anonymous said...

$(jot - 1 16 2)

can be a replacement of the following two:

for((i=1;i<=16;i+=2))
$(seq 1 2 16)

** jot prints sequential or random
data

More of jot : http://unstableme.blogspot.com/2007/12/jot-print-sequential-or-random-data.html

// Jadu

Unknown said...

Thanks Jadu, jot is yet another little utility I'd never heard of before!

Like your blog too..

Anonymous said...

for x in {1..4}; do echo $x; done

Unknown said...

@anonymous:

for x in {1..4}; do echo $x; done

.. works OK with literals, but how do you substitute the range with a variable?

e.g.
v_range=1..4
for x in {${v_range}}; do echo $x; done
# doesn't work, nor does:
v_start=1
v_end=4
for x in {${v_start}..${v_end}}; do echo $x; done
# nor does:
for x in {v_start..v_end}; do echo $x; done

spamtrap said...

a=1; b=10; for i in `seq $a $b`; do echo $i; done

works for me

spamtrap said...

$a=1
$b=10
for i in 'seq $a $b`;do echo $i; done

Works for me.

Unknown said...

@Szilard good thought, although I think it still requires some parsing in order to deal with parameters supplied like "1..4" or "1-3", which was the original problem I was facing