Assign variables inside for loops - bash

I am trying a small code which is
for(( i =0;i<2;i++ )); do p$i=\"pra$i\"; done
expected output is:
Variable must be assigned
p0="pra0"
p1="pra1"
But bash is taking that as command and am getting output as
p0="pra0": command not found
p1="pra1": command not found
Thanks

Use eval to have the value evaluated and stored as you want:
$ for(( i =0;i<2;i++ )); do eval p$i=\"pra$i\"; done
$ echo $p1
pra1
Or better with declare (thanks chepner as always!):
$ for(( i =0;i<2;i++ )); do declare "p$i=pra$i"; done
$ echo $p1
pra1

for (( i =0;i<2;i++ )); do
printf -v "p$i" '%s' "pra$i"
done

Related

Bash: write args from back. Can I do this better than N^2?

if [[ $1 == "-r" ]]
then
arr=()
i=0
for var in ${#:2}
do
arr[$i]+=$var
((i++))
done
((i--))
for (( j=$i;$j >= 0;j=$j-1 ))
do
echo ${arr[$j]}
done
fi
this is my script to wrote args from last to first one if I add -r.
Can I do this better?
Because now this is N^2. So I feel like I could do this better but I have no idea how. Any advice?
Just index arguments from the back:
for ((i=1;i<=$#;++i)); do
echo "${#: -$i:1}"
done
See ${parameter:offset:length} expansion in bash manual shell parameter expansion.
You can loop over the arguments from the last to the second. Use indirection to use the number as the name of the variable:
for ((i=$#; i>1; --i)) ; do
printf '%s\n' "${!i}"
done

Sum of integer variables bash script

How can I do the sum of integers with bash script I read some variables with a for and I need to do the sum.
I have written the code like this:
Read N
Sum=0
for ((i=1;i<=N;i++))
do
read number
sum=sum+number
done
echo $sum
Use the arithmetic command ((...)):
#! /bin/bash
read n
sum=0
for ((i=1; i<=n; i++)) ; do
read number
((sum+=number))
done
echo $sum
#!/bin/bash
echo "Enter number:"
read N
re='^[0-9]+$'
if ! [[ ${N} =~ ${re} ]]
then
echo "Error. It's not a number"
exit 1
fi
Sum=0
for ((i=1;i<=N;i++))
do
sum=$((${sum} + ${i}))
done
echo "${sum}"
Well, not a straight bash solution, but you can also use seq and datamash (https://www.gnu.org/software/datamash/):
#!/bin/bash
read N
seq 1 $N | datamash sum 1
It is really simple (and it has its limitations), but it works. You can use other options on seq for increments different than 1 and so on.
It is also possible to declare a variable as an integer with declare -i. Any assignment to that variable is then evaluated as an arithmetic expression:
#!/bin/bash
declare -i sum=0
read -p "Enter n: " n
for ((i=1; i<=n; i++)) ; do
read -p "Enter number #$i: " number
sum+=number #sum=sum+number would also work
done
echo "Sum: $sum"
See Bash Reference Manual for more information. Using arithmetic command ((...)) is preferred, see choroba's answer.
$ declare -i var1=1
$ var2=1
$ var1+=5
$ echo "$var1"
6
$ var2+=5
$ echo "$var2"
15
This can be a tad confusing as += behaves differently depending on the variable's attributes. It's therefore better to explicitly use ((...)) for arithmetic operations.

Increment variable value by 1 (shell programming)

I can't seem to be able to increase the variable value by 1. I have looked at tutorialspoint's Unix / Linux Shell Programming tutorial but it only shows how to add together two variables.
I have tried the following methods but they don't work:
i=0
$i=$i+1 # doesn't work: command not found
echo "$i"
$i='expr $i+1' # doesn't work: command not found
echo "$i"
$i++ # doesn't work*, command not found
echo "$i"
How do I increment the value of a variable by 1?
You can use an arithmetic expansion like so:
i=$((i+1))
or declare i as an integer variable and use the += operator for incrementing its value.
declare -i i=0
i+=1
or use the (( construct.
((i++))
The way to use expr:
i=0
i=`expr $i + 1`
The way to use i++ (unless you're running with -e/-o errexit):
((i++)); echo $i;
Tested in gnu bash.
you can use bc as it can also do floats
var=$(echo "1+2"|bc)
These are the methods I know:
ichramm#NOTPARALLEL ~$ i=10; echo $i;
10
ichramm#NOTPARALLEL ~$ ((i+=1)); echo $i;
11
ichramm#NOTPARALLEL ~$ ((i=i+1)); echo $i;
12
ichramm#NOTPARALLEL ~$ i=`expr $i + 1`; echo $i;
13
Note the spaces in the last example, also note that's the only one that uses $i.

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

How can I get the length of all arguments given to a function in bash?

I'd like to get the length of the string that I get when i use "$*" in my function.
I tried:
echo ${#"$*"}
and
echo ${#"*"}
both gave me a bad substitution error.
I don't think you can do it in a single command. However, this seems to work:
#!/bin/bash
a="$#"
echo "${#a}"
Using a temporary variable is the only one basic way, and you need to unset IFS or set it to empty string to prevent spaces in between. And use $* not $# for it would give you spaces in between:
IFS= eval "__=\"\$*\""
echo "${#__}"
Another way is to loop through all strings:
L=0; for __; do (( L += ${#__} )); done
echo "$L"
You can use one of the following.
expr length "$*"
echo "$*" | awk '{print length}'
$# holds the number of positional parameters passed to the function.
Try it:
#!/bin/bash
t() {
echo "num args=$#"
echo "all $*"
}
t "$#"

Resources