Bash script to give n numbers and print even numbers - linux

I'm trying to write a bash script for
"Given a positive integer N greater than 1, make a script to show the
even numbers between 0 and N. Ex .: The number 12 has been read. The
program must have as output: 0, 2, 4, 6, 8, 10 and 12;"
So far I did like this:
ex5.sh
#!/bin/bash
echo "Number :"
read num;
for (( i = 1; i >= $num; i++ ))
do
if [ $(($i % 2)) -eq 0 ]
then
echo $i
fi
done
When i compile, it doesn't print numbers. I couldn't find where is the problem
I tried using for-in loop as well
#!/bin/bash
echo "Number :"
read num;
for i in $num
do
if [ $(($i % 2)) -eq 0 ]
then
echo $i
fi
done
This time only print the number that i put as a input. For example, I put 4 in terminal it prints 4 as well
Many thanks

This way can make your code working:
echo -n "Number : "
read num;
for i in $(seq 0 $num)
do
if [ $(expr $i % 2) == 0 ]
then
echo $i
fi
done
bash ex5.sh
Number : 12
0
2
4
6
8
10
12

`
echo -n "Number : "
read num;
for i in $(seq 0 $num)
do
if [ $((num%2)) -eq 0 ]
then
echo $i
fi
done
`

#!/bin/bash
read -p "Number: " num
awk '{for(i=0;i<=$1;i++) if(i%2 == 0) print i}'<<<$num
./printNumbers.sh
Number: 8
0
2
4
6
8
# to get a list use printf
awk '{for(i=0;i<=$1;i++) if(i%2 == 0) printf i","}'<<<$num | sed 's/,$//'
./printNumbers.sh
Number: 8
0,2,4,6,8

#!/usr/bin/env bash
read -p 'Number: ' num
seq 0 2 "$num"

it's <= not >=
#!/bin/bash
echo "Number :"
read num;
for (( i = 1; i <= $num; i++ ))
do
if [ $(($i % 2)) -eq 0 ]
then
echo $i
fi
done

Related

how to find sum of even no till 100 in linux

what should be condition for while before adding while loops it prints even no upto 100 but I need to print sum of even numbers
#!/bin/bash
sum=0
for((n=2;n<=100;n=n+2))
do
echo $n
while [[$n 0]] # what should be condition for while loop
do
sum= `expr sum + $n`
done
echo "sum is $sum "
done
Does this count ^_* :
kent$ seq -s + 2 2 100|bc
2550
k=0;
for i in {1..100}; do
if [[ $(( i % 2 )) == 0 ]]; then
let k=k+i
fi ; done
echo $k
Prints
2550
or this:
k=0; for i in {1..100}; do
if (( i % 2 == 0 )); then
(( k=k+i )) ; fi ; done ; echo $k
You shouldn't have the while loop at all. You're already iterating with the for loop.
#!/bin/bash
sum=0
for((n=2;n<=100;n=n+2))
do
echo $n
((sum+=n))
done
echo "sum is $sum "

How to write script for arithmetic mean of even numbers

I have to write a script in bash where I have to provide 10 numbers to the table. Then script have to write the content out and arithmetic mean of even numbers. I did like 90% of the script, but I can't find out how to extract information about quantity of even numbers that is needed for arithmetic mean.
Here is my code:
echo "Provide data:"
i=0
for (( i = 0 ; i < 10; i++ ))
do
echo "Provide $[$i+1] number:"
read x
if [ "$x" = "" ]
then
break
else
table[$i]=$x
fi
done
echo "Provided data: ${table[*]}"
result=0
for (( i = 0 ; i < 10; i++))
do
res=$[${table[i]}%2]
if [ $res -eq 0 ]
then
echo "Number ${table[i]} is even"
result=$[$result+${table[$i]}]
fi
done
echo "SUM:$[$result]"
ignoring data input adding only odd inputs can look like :
$ cat c.sh
#!/bin/bash
declare -A xDarray
sum=0
xDarray[0 1]=1
xDarray[0 2]=3
xDarray[1 0]=2
xDarray[2 0]=4
for var in ${xDarray[#]}
do
if [ $(( $var & 1 )) == 0 ] ; then
echo $var is even
i+=1
tab[$i]=$var
sum=$(( $sum + $var))
fi
done
var=$(echo ${tab[#]} | sed 's/ / + /g' )
echo $var = $sum
result in
$ ./c.sh
2 is even
4 is even
2 + 4 = 6
$
whatever the number of data is used it would work
I let you work around your data input
Here are some suggested modifications for your script, syntax is simple.
#!/bin/bash
arr=()
for (( i=1;i<=10;i++ )); do
number=''
while [[ ! $number =~ ^[0-9]+$ ]]; do
printf "Please enter number $i:\n"
read number
done
arr+=($number)
done
printf "\nProvided numbers:"
printf " %d" "${arr[#]}"
printf "\nEven numbers:"
s=0
n=0
for x in "${arr[#]}"; do
if ! (( x % 2 )); then
printf " %d" "$x"
s=$(( s + x ))
(( n++ ))
fi
done
m=$(( s / n ))
printf "\nMean of the %d even numbers: %d / %d = %d\n" "$n" "$s" "$n" "$m"
Use an array arr to hold the input numbers, declare with arr=(), append numbers with arr+=($x), we refer only ${arr[#]} for all the items and we avoid any other complex array references, indices etc.
Every input number is tested against regular expression ^[0-9]+$ which means one or more digits (and only digits) with the =~ operator, and if this is not true, we prompt again for the same i-th input number.
Also we prefer printf for printing.
The last loop is the standard array loop, where we use again the arithmetic expansion syntax to find the even numbers, to add them to the sum and get the mean of them (result is an integer).
If you want to print a decimal result, e.g. with 2 floating points, you could use bc and printf "%f" like this:
m=$( bc <<< "scale=2; $s/$n" )
printf "%.2f" "$m"

Bash script: max,min,sum - many sources as parameter

Is it possible to write a script that reads the file containing numbers (one per line) and writes their maximum, minimum and sum. If the file is empty, it will print an appropriate message. The name of the file is to be given as the parameter of the script. I mange to create below script, but there are 2 errors:
./4.3: line 20: syntax error near unexpected token `done'
./4.3: line 20: `done echo "Max: $max" '
Is it possible to add multiple files as parameter?
lines=`cat "$1" | wc -l`
if [ $lines -eq 0 ];
then echo "File $1 is empty!"
exit fi min=`cat "$1" | head -n 1`
max=$min sum=0
while [ $lines -gt 0 ];
do num=`cat "$1" |
tail -n $lines`
if [ $num -gt $max ];
then max=$num
elif [ $num -lt $min ];
then min=$num fiS
sum=$[ $sum + $num] lines=$[ $lines - 1 ]
done echo "Max: $max"
echo "Min: number $min"
echo "Sum: $sum"
Pretty compelling use of GNU datamash here:
read sum min max < <( datamash sum 1 min 1 max 1 < "$1" )
[[ -z $sum ]] && echo "file is empty"
echo "sum=$sum; min=$min; max=$max"
Or, sort and awk:
sort -n "$1" | awk '
NR == 1 { min = $1 }
{ sum += $1 }
END {
if (NR == 0) {
print "file is empty"
} else {
print "min=" min
print "max=" $1
print "sum=" sum
}
}
'
Here's how I'd fix your original attempt, preserving as much of the intent as possible:
#!/usr/bin/env bash
lines=$(wc -l "$1")
if [ "$lines" -eq 0 ]; then
echo "File $1 is empty!"
exit
fi
min=$(head -n 1 "$1")
max=$min
sum=0
while [ "$lines" -gt 0 ]; do
num=$(tail -n "$lines" "$1")
if [ "$num" -gt "$max" ]; then
max=$num
elif [ "$num" -lt "$min" ]; then
min=$num
fi
sum=$(( sum + num ))
lines=$(( lines - 1 ))
done
echo "Max: $max"
echo "Min: number $min"
echo "Sum: $sum"
The dealbreakers were missing linebreaks (can't use exit fi on a single line without ;); other changes are good practice (quoting expansions, useless use of cat), but wouldn't have prevented your script from working; and others are cosmetic (indentation, no backticks).
The overall approach is a massive antipattern, though: you read the whole file for each line being processed.
Here's how I would do it instead:
#!/usr/bin/env bash
for fname in "$#"; do
[[ -s $fname ]] || { echo "file $fname is empty" >&2; continue; }
IFS= read -r min < "$fname"
max=$min
sum=0
while IFS= read -r num; do
(( sum += num ))
(( max = num > max ? num : max ))
(( min = num < min ? num : min ))
done < "$fname"
printf '%s\n' "$fname:" " min: $min" " max: $max" " sum: $sum"
done
This uses the proper way to loop over an input file and utilizes the ternary operator in the arithmetic context.
The outermost for loop loops over all arguments.
You can do the whole thing in one while loop inside a shell script. Here's the bash version:
s=0
while read x; do
if [ ! $mi ]; then
mi=$x
elif [ $mi -gt $x ]; then
mi=$x
fi
if [ ! $ma ]; then
ma=$x
elif [ $ma -lt $x ]; then
ma=$x
fi
s=$((s+x))
done
if [ ! $ma ]; then
echo "File is empty."
else
echo "s=$s, mi=$mi, ma=$ma"
fi
Save that script into a file, and then you can use pipes to send as many input files into it as you wish, like so (assuming the script is called "mysum"):
cat file1 file2 file3 | mysum
or for a single file
mysum < file1
(Make sure, the script is executable and on the $PATH, otherwise use "./mysum" for the script in the current directory or indeed "bash mysum" if it isn't executable.)
The script assumes that the numbers are one per line and that there's nothing else on the line. It gives a message if the input is empty.
How does it work? The "read x" will take input from stdin line-by-line. If the file is empty, the while loop will never be run, and thus variables mi and ma won't be set. So we use this at the end to trigger the appropriate message. Otherwise the loop checks first if the mi and ma variables exist. If they don't, they are initialised with the first x. Otherwise it is checked if the next x requires updating the mi and ma found thus far.
Note that this trick ensures that you can feed-in any sequence of numbers. Otherwise you have to initialise mi with something that's definitely too large and ma with something that's definitely too small - which works until you encounter a strange number list.
Note further, that this works for integers only. If you need to work with floats, then you need to use some other tool than the shell, e.g. awk.
Just for fun, here's the awk version, a one-liner, use as-is or in a script, and it will work with floats, too:
cat file1 file2 file3 | awk 'BEGIN{s=0}; {s+=$1; if(length(mi)==0)mi=$1; if(length(ma)==0)ma=$1; if(mi>$1)mi=$1; if(ma<$1)ma=$1} END{print s, mi, ma}'
or for one file:
awk 'BEGIN{s=0}; {s+=$1; if(length(mi)==0)mi=$1; if(length(ma)==0)ma=$1; if(mi>$1)mi=$1; if(ma<$1)ma=$1} END{print s, mi, ma}' < file1
Downside: if doesn't give a decent error message for an empty file.
a script that reads the file containing numbers (one per line) and writes their maximum, minimum and sum
Bash solution using sort:
<file sort -n | {
read -r sum
echo "Min is $sum"
while read -r num; do
sum=$((sum+num));
done
echo "Max is $num"
echo "Sum is $sum"
}
Let's speed up by using some smart parsing using tee, tr and calculating with bc and if we don't mind using stderr for output. But we could do a little fifo and synchronize tee output. Anyway:
{
<file sort -n |
tee >(echo "Min is $(head -n1)" >&2) >(echo "Max is $(tail -n1)" >&2) |
tr '\n' '+';
echo 0;
} | bc | sed 's/^/Sum is /'
And there is always datamash. The following willl output 3 numbers, being sum, min and max:
<file datamash sum 1 min 1 max 1
You can try with a shell loop and dc
while [ $# -gt 0 ] ; do
dc -f - -e '
['"$1"' is empty]sa
[la p q ]sZ
z 0 =Z
# if file is empty
dd sb sc
# populate max and min with the first value
[d sb]sY
[d lb <Y ]sM
# if max keep it
[d sc]sX
[d lc >X ]sN
# if min keep it
[lM x lN x ld + sd z 0 <B]sB
lB x
# on each line look for max, min and keep the sum
[max for '"$1"' = ] n lb p
[min for '"$1"' = ] n lc p
[sum for '"$1"' = ] n ld p
# print summary at end of each file
' <"$1"
shift
done

How to Do a For Loop Instead of a While Loop in Shell Scripting

I'm trying to implement for loops instead of while loops but have no idea how too. This is a while loop script I created. How would I make this into a for loop instead of a while loop? I'm not really understanding how for loops work.
#!/bin/bash
read -p "Number of Papers To Grade:
" numpap
av=$numpap
while [ $av -gt 0 ];
do
av=$(($av - 1))
echo "Enter a Number (1-100): "
read num
if [[ $num -ge 1 && $num -le 100 ]] ; then
echo ""
else
echo "Enter a Number Between 1-100
"
av=$(($av + 1))
total=$(($total - num))
fi
total=$(($total + num))
done
averag=$(($total/$numpap))
echo Average Grade = $averag%
echo "Done"
#!/bin/bash
var=5
for ((value=var; value>0; --value))
do
echo $value
done
This gives the output :
5
4
3
2
1
You can have a look at more ways to write loops using while / for / until : here
I modified your script to run using a for loop:
#!/bin/bash
read -p "Number of Papers To Grade:" numpap
for ((av=numpap; av>0; av--))
do
echo "Enter a Number (1-100): "
read num
if [[ $num -ge 1 && $num -le 100 ]] ; then
echo ""
else
echo "Enter a Number Between 1-100"
av=$(($av + 1))
total=$(($total - num))
fi
total=$(($total + num))
done
averag=$(($total/$numpap))
echo Average Grade = $averag%
echo "Done"

Bubble sort in Linux/Unix shell scripting

I am trying to perform bubble sort is Unix shell script. Why is my code not working?
a=(10 8 20 25 12)
for ((i=0;i<5;i++))
do
for((j=0;j<5;j++))
do
if ((${a[j]} > ${a[$((j+1))]}))
then
v=${a[$j]}
a[$j]=${a[$((j+1))]}
a[$((j+1))]=$v
fi
done
done
echo ${a[*]}
echo "end..."
I guess this is homework. therefore I don't give codes, just point out the errors in your codes:
for((j=0;j<5;j++)) then read a[j+1], here would be problem because when j=4, j+1 doesn't exist
fix that, your program will sort.
Try this:
echo "Enter size of array";
read n; #get the size of array from user.
echo "Enter the array";
read -a arr; #get the array form user eg: 2 3 4 5 6
echo "Orignal array is: ${arr[*]}"; #print orignal array
flag=1;
for (( i = 0; i < $n-1; i++ ))
do
flag=0;
for ((j = 0; j < $n-1-$i; j++ ))
do
if [[ ${arr[$j]} -gt ${arr[$j+1]} ]]
then
temp=${arr[$j]};
arr[$j]=${arr[$j+1]};
arr[$j+1]=$temp;
flag=1;
fi
done
if [[ $flag -eq 0 ]]; then
break;
fi
done
echo "Final sorted Array is ${arr[*]}";

Resources