bash script, to use a variable in a variable - bash

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

Related

linux bash script error

when I try to run this script
for ((i=1; i<=5; i++))
do
for ((j=1; j<=5; j++))
do
echo –n $i
done
echo " "
done
I get this error:
syntax error near unexpected token '(('
for ((j=1; j<=5; j++))"
It appears you're running this with an interpreter that is not bash. I've indented your code, but it worked just fine without indentation too.
$ cat test.bash
for ((i=1; i<=5; i++))
do
for ((j=1; j<=5; j++))
do
echo –n $i
done
echo " "
done
$ /bin/sh test.bash
/tmp/test.bash: 1: Syntax error: Bad for loop variable
$ echo $BASH_VERSION
5.0.11(1)-release
$ bash test.bash
–n 1
–n 1
–n 1
–n 1
–n 1
–n 2
–n 2
…
As you can see, echo -n is not reliable. Change that line to printf %s $i to resolve that and your output will become:
11111
22222
33333
44444
55555
If you are invoking it with bash, perhaps your bash version is too old? You can use for i in {1..5} for something more compatible (but not valid POSIX) or you could use for i in 1 2 3 4 5 for full POSIX compatibility. If you have GNU coreutils, you could do for i in $(seq 5) instead (see man seq).
To better approach your intended logic, you could also consider a while loop:
i=0
while [ $((++i)) -le 5 ]
do
j=0
while [ $((++j)) -le 5 ]
do
printf %s $i
done
echo " "
done
This initializes i to zero before a while loop, then increments it in the test condition when comparing it to five; the first loop's first iteration increments i to 1, finds that it is indeed less than or equal (-le) to 5, and therefore continues.
(I'm using a $((…)) arithmetic expression and ++i inside it since the more common i++ would return the value of i before it is incremented while ++i returns the value of i after it is incremented.)

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

Loop in UNIX is not working

Please tell me what is wrong with the UNIX code below.
#!/bin/ksh
p=10
for i in $p
do
echo $i
done
i am expecting output as
1
2
3
.
.
.
but the output am getting is just 10
I need for loop not while loop.
in ksh
#!/bin/ksh
p=10
i=1
while ((i<=p)); do
echo $i
i=$((i+1))
done
or
#!/bin/ksh
# with for you can only do this
for i in 1 2 3 4 5 6 7 8 9 10; do
echo $i
done
in bash it works as expected
#!/bin/bash
p=10
for (( i=1; i<=p; i++ )); do
echo $i
done
there is a Linux command seqthat can be used for both ksh and bash. But it is a Linux command. So this will not work on Solaris or other Unix systems that don't have the progrtam seq installed.
# on Linux, bash or ksh
p=10
for i in $(seq $p); do
echo $i
done
The following uses only shell built-ins and therefore will work for all bash installations (e.g. on Solaris) but not for ksh
#!/bin/bash
p=10
for i in `eval echo {1..$p}`; do
echo $i
done
This complicated construct is necessary because of brace expansion occurrs before variable expansion
You have to assign a range. Otherwise the loop can't work. This should do it:
#!/bin/ksh
p=10
for i in {0..$p}
do
echo $i
done
#fedorqui: You are right, I absolutely missed that. When I do stuff like this in Bash (I don't know if it's the same for KornShell), I go like:
for ((i=0; i<$p; i++))
in UNIX KSH
#!/bin/ksh
while [ ${i:=1} -le 10 ]
do
echo "$i"
let i+=1
done

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