msysgit: Git bash misses the `seq` command. Is there an alternative? - shell

I use seq a lot in my simulation shell scripts. The Git bash does not provide it, thus I am looking for an alternative.
Is there an alternative to seq that is part of the commands supported by the Git bash?
Current Solution: Based on Ignacio's answer I wrote a little helper script that provides my legacy scripts with a simple seq function. I also noticed, when using echo {1..10} with variables, you need to use eval to get the sequence output instead of the unexpanded expression:
a=0; b=5
eval echo {$a..$b} # outputs 0 1 2 4 5
echo {$a..$b} # outputs {0..5}
Here is my new seq.sh:
#!/bin/bash
# check for the real seq and export a new seq if not found
# import this script via `source ./seq.sh`
#
hasSeq(){
which seq >/devnull 2>&1
}
mySeq(){
case $# in
1) eval echo {1..$1};;
2) eval echo {$1..$2};;
3) echo "seq(3) not supported" 1>&2;;
esac
}
if ! hasSeq; then
seq(){
mySeq $*
}
fi
hasSeq || export -f seq

Assuming the version of bash is recent enough, you could use brace expansion.
$ echo {1..16}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Or... you know...

Related

Print all numbers between two given numbers

I'm working on a Bash script which that takes in two integers and outputs all the numbers in between the two. It would look something like this:
Input:
bash testScript 3 10
3
4
5
6
7
8
9
10
This is some code that I wrote that I thought would work but I haven't had much luck getting it to work yet.
read myvar
read myvar2
while [ $myvar -le myvar2 ]
do
echo $myvar
myvar=$(($myvar+1))
//timer in-between numbers
sleep .5
done
Bash supports c style for loops using a double parenthesis construct:
$ for ((x=3; x<=10; x++)); { echo $x; }
3
4
5
6
7
8
9
10
Or, brace expansion:
$ for i in {3..6}; do echo $i; done
3
4
5
6
Problem with brace expansion is you need to use eval to use variables...
A common GNU utility for this is seq but it is not POSIX, so may not be on every *nix. If you want to write a similar function in Bash, it would look like this:
my_seq ()
# function similar to seq but with integers
# my_seq [first [incr]] last
{
incr=1
start=1
if [[ $# -gt 2 ]]; then
start=$1
incr=$2
end=$3
elif [[ $# -gt 1 ]]; then
start=$1
end=$2
else
end=$1
fi
for ((x=start; x<=end; x+=incr)); { echo $x; }
}
Then call that with 1, 2 or 3 arguments:
$ my_seq 30 10 60
30
40
50
60
with brace expansion
$ echo {3..10} | tr ' ' '\n'
or for variables with eval
$ a=3; b=10; eval echo {$a..$b} | ...
or, if you have awk
$ awk -v s=3 -v e=10 'BEGIN{while(s<=e) print s++}'
Use positional parameters:
myvar=$1
myvar2=$2
while [ $myvar -le $myvar2 ]
do
echo $myvar
myvar=$(($myvar+1))
#timer in-between numbers
sleep .5
done
Output:
scottsmudger#ns207588:~ $ bash test 1 5
1
2
3
4
5
See http://www.tldp.org/LDP/abs/html/othertypesv.html
Your posted codes are not aligned properly, not sure if it's your actual codes. But only problem other than the alignment is you missed a $ for myvar2 in the while statment.
read myvar
read myvar2
while [ $myvar -le $myvar2 ]
do
echo $myvar
myvar=$(($myvar+1))
#//timer in-between numbers
sleep .5
done

How to use eval for a variable inside a for in using Bash?

When I try doing this:
a={0..10}
for i in $a
do
echo $i
done
The output is just: {0..10}
printf -v a "%d " {0..10}
for i in $a
do
echo $i
done
Output:
0
1
2
3
4
5
6
7
8
9
10
This is one of many situations when the traditional tool, seq, is more useful than bash's brace notation:
a=$(seq 0 10)
for i in $a
do
echo $i
done
The above produces:
0
1
2
3
4
5
6
7
8
9
10
An additional advantage of seq is that it works with variables, something that bash's braces won't do. For example:
$ count=5
$ seq 0 $count
0
1
2
3
4
5
Contrast the above with:
$ echo {0..$count}
{0..5}
The above failed because bash's brace notation does not accept variables for arguments.
Mac OSX
seq is available on OSX for versions 10.8+ and maybe also 10.7. On older versions, the similar, but not identical, BSD tool jot can be used instead.
You can use:
for i in $(eval "echo $a"); do echo $i; done
0
1
2
3
4
5
6
7
8
9
10
But better (safer) than eval alternative in BASH is this arithmetic direecitve:
for ((i=0; i<=10; i++)); do echo $i; done
Your code will work if you do
a=$(echo {0..10})
Instead of a={0..10}, which will be interpreted as a='{0..10}' literally.

How in OS/X to get 'seq' command-line functionality?

I'm still on Snow Leopard (I know...) so forgive if this is fixed in one of the later versions of OS/X, but I want to do standard "seq" aka:
for i in `seq 1 100` ; do
cat /whatever > $i.txt ;
done
I thought installing GNU tools would do it, but apparently not.
On my mac both of these work (OS X 10.8.5)
Andreas-Wederbrands-MacBook-Pro:~ raven$ for i in {1..10}; do echo $i; done
1
2
3
4
5
6
7
8
9
10
Andreas-Wederbrands-MacBook-Pro:~ raven$ for i in `seq 1 10`; do echo $i; done
1
2
3
4
5
6
7
8
9
10
In Snow Leopard, you can use the jot command, which can produce sequential data like seq (and more, see the man page for details).
$ jot 5
1
2
3
4
5
$ jot 3 5
5
6
7
No need for a tool such as seq -- bash (like ksh and zsh) has syntax built-in:
# bash 3.x+
for ((i=0; i<100; i++)); do
...
done
...or, for bash 2.04+, zsh, and ksh93:
i=0; while ((i++ <= 100)); do
...
done
...or, for absolutely any POSIX-compliant shell:
while [ $(( ( i += 1 ) <= 100 )) -ne 0 ]; do
...
done
bash also supports expansions such as {0..100}, but that doesn't support variables as endpoints, whereas the for-loop syntax is more flexible.
Or, just add this to your bash profile:
function seq {
if [ $1 > $2 ] ; then
for ((i=$1; i<=$2; i++))
do echo $i
done
else
for ((i=$1; i>=$2; i--))
do echo $i
done
fi
}
It's not that hard.

Is it possible to use a variable in for syntax in bash?

I wonder If it is possible to write "for i in {n..k}" loop with a variable.
For example;
for i in {1..5}; do
echo $i
done
This outputs
1
2
3
4
5
On the other hands
var=5
for i in {1..$var}; do
echo $i
done
prints
{1..5}
How can I make second code run as same as first one?
p.s. I know there is lots of way to create a loop by using a variable but I wanted to ask specifically about this syntax.
It is not possible to use variables in the {N..M} syntax. Instead, what you can do is use seq:
$ var=5
$ for i in $(seq 1 $var) ; do echo "$i"; done
1
2
3
4
5
Or...
$ start=3
$ end=8
$ for i in $(seq $start $end) ; do echo $i; done
3
4
5
6
7
8
While seq is fine, it can cause problems if the value of $var is very large, as the entire list of values needs to be generated, which can cause problems if the resulting command line is too long. bash also has a C-style for loop which doesn't explicitly generate the list:
for ((i=1; i<=$var; i++)); do
echo "$i"
done
(This applies to constant sequences as well, since {1..10000000} would also generate a very large list which could overflow the command line.)
You can use eval for this:
$ num=5
$ for i in $(eval echo {1..$num}); do echo $i; done
1
2
3
4
5
Please read drawbacks of eval before using.

Bourne Shell For i in (seq)

I want to write a loop in Bourne shell which iterates a specific set of numbers. Normally I would use seq:
for i in `seq 1 10 15 20`
#do stuff
loop
But seemingly on this Solaris box seq does not exist. Can anyone help by providing another solution to iterating a list of numbers?
try
for i in 1 10 15 20
do
echo "do something with $i"
done
else if you have recent Solaris, there is bash 3 at least. for example this give range from 1 to 10 and 15 to 20
for i in {1..10} {15..20}
do
echo "$i"
done
OR use tool like nawk
for i in `nawk 'BEGIN{ for(i=1;i<=10;i++) print i}'`
do
echo $i
done
OR even the while loop
while [ "$s" -lt 10 ]; do s=`echo $s+1|bc`; echo $s; done
You can emulate seq with dc:
For instance:
seq 0 5 120
is rewritten as:
dc -e '0 5 120 1+stsisb[pli+dlt>a]salblax'
Another variation using bc:
for i in $(echo "for (i=0;i<=3;i++) i"|bc); do echo "$i"; done
For the Bourne shell, you'll probably have to use backticks, but avoid them if you can:
for i in `echo "for (i=0;i<=3;i++) i"|bc`; do echo "$i"; done
#!/bin/sh
for i in $(seq 1 10); do
echo $i
done
I find that this works, albeit ugly as sin:
for i in `echo X \n Y \n Z ` ...
for i in `seq 1 5 20`; do echo $i; done
Result:
5
10
15
20
$ man seq
SEQ(1) User Commands SEQ(1)
NAME
seq - print a sequence of numbers
SYNOPSIS
seq [OPTION]... LAST
seq [OPTION]... FIRST LAST
seq [OPTION]... FIRST INCREMENT LAST

Resources