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
Related
I need a bash script to find the sum of the absolute value of integers separated by spaces. For instance, if the input is:
1 2 -3
the script should print 6 to standard output
I have:
while read x ; do echo $(( ${x// /+} )) ; done
which gives me
0
Without over complicated things, how would I include an absolute value of each x in that statement so the output would be:
6
With Barmar's idea:
echo "1 2 -3" | tr -d - | tr ' ' '+' | bc -l
Output:
6
You have almost done it, but the -s must have been removed from the line read:
while read x; do x=${x//-}; echo $(( ${x// /+} )); done
POSIX friendly implementation without running a loop and without spawning a sub-shell:
#!/usr/bin/env sh
abssum() {
IFS='-'
set -- $*
IFS=' '
set -- $*
IFS=+
printf %d\\n $(($*))
}
abssum 1 2 -3
Result:
6
In order to obtain the results of consecutive numbers, a bash script was created as follows.
However, the results did not come out as intended.
#!/bin/bash
test="i am $i"
for i in {1..10}
do
echo "$test"
done
result
sh test.sh
i am
i am
i am
i am
i am
i am
i am
i am
i am
i am
But the result I want is...
As shown below, how do we deal with the variables to get the results?
i am 1
i am 2
i am 3
i am 4
i am 5
i am 6
i am 7
i am 8
i am 9
i am 10
Use $i outside of the variable
#!/bin/bash
test="i am "
for i in {1..10}
do
echo $test $i
done
Also you can use ${i} inside of the variable
#!/bin/bash
for i in {1..10}
do
test="i am ${i}"
echo $test
done
The result is:
i am 1
i am 2
i am 3
i am 4
i am 5
i am 6
i am 7
i am 8
i am 9
i am 10
Or you can replace substr with anything you want inside.
For example
#!/bin/bash
test="I am SUBSTR"
for i in {1..10}
do
echo ${test/SUBSTR/$i}
done
When you have multiple variables, I know this solution:
#!/bin/bash
test="I am SUBSTR and STR2"
for i in {1..10}
do
o=${test/SUBSTR/$i}
echo ${o/STR2/$i*$i}
done
Using sed also can help
#!/bin/bash
test="I am SUBSTR and STR2"
for i in {1..10}
do
echo $test | sed -e 's/SUBSTR/'$i'/;s/STR2/'$i++'/'
done
You need to write a function in order to delay the evaluation.
#!/bin/bash
message () { echo "i am $1"; }
for i in {1..10}
do
message $i
done
Or the following, if you just want to craft the message.
#!/bin/bash
message () { echo "i am $1"; }
for i in {1..10}
do
test="$(message $i)"
echo "$test"
done
#!/bin/bash
test='i am $i'
for i in {1..10}
do
eval echo "$test"
done
or
#!/bin/bash
test='echo "i am $i"'
for i in {1..10}
do
eval "$test"
done
Example:
yanyong#master:~$ test='echo "i am $i"'; for i in {1..10}; do eval "$test"; done
i am 1
i am 2
i am 3
i am 4
i am 5
i am 6
i am 7
i am 8
i am 9
i am 10
References:
https://man7.org/linux/man-pages/man1/eval.1p.html
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.
I have a log line that I am pulling from bash like:
There are 5 apples and 7 oranges
And I want to get the 5 and 7 into bash variables and am having problems doing so.
awk '{ print $3, $6 }' won't work due to the fact that their position might change, if there are bananas. Bonus points if the digits can be associated with their fruits.
Thanks in advance
and to get the fruits:
echo 'There are 5 apples and 7 oranges' | grep -o -E '[[:digit:]]+ [[:alpha:]]+'
A bash-only method, tested with bash v4:
str=" There are 5 apples, 12 bananas and 7 oranges"
i=0
while [[ "$str" =~ ([0-9]+)" "([a-z]+)(.*) ]] ; do
num[$i]=${BASH_REMATCH[1]}
type[$i]=${BASH_REMATCH[2]}
str=${BASH_REMATCH[3]}
(( i++ ))
done
for (( i=0; i<${#num[#]}; i++ )); do
printf "%4d\t%s\t%s\n" $i ${num[$i]} ${type[$i]}
done
outputs
0 5 apples
1 12 bananas
2 7 oranges
Grep will do this:
echo 'There are 5 apples and 7 oranges' | grep -o -E '[[:digit:]]+'
Slightly more compact version:
echo 'There are 5 apples and 7 oranges' | egrep -o '[0-9]+ \w+'
Note however that \w is synonymous with [:alnum:], and will thus match "appl3s" as well, for example.
Well, shell is a strange language, and you can do nice things. For example:
a="there are 7 apples"
for i in $a; do
case $i in
[0-9]*)
value=$i
expectname=1
;;
*)
test -n "$expectname" && name=$i
expectname=
;;
esac
done
echo $value
echo $name
If you have more than one occurrence, you can fill an array, or a bash map.
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