I am writing a couple of bash scripts which I wish to call within another bash script but I can't seem to get these two examples online to work. It keeps telling me that there is an unexpected error near "r" and one near "mychoice" though it doesn't get resolved when I make the changes. The two classes are to generate a prime numbers test which if it works, I hope to be able to stress a cpu. the other class is just to dynamically select how long to run sar rather than having to hard code in sar 1 30 for example. Does anyone know what is wrong with these classes? Thanks in advance.
primetest class
#!/bin/bash
#
# primes.sh - find all prime numbers up to a certain number
# 2008 - Mike Golvach - eggi#comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
factorial () {
local factorial_count=$1
if [ "$factorial_count" -eq 0 ]
then
factorial_count=1
fi
for (( factor=$((factorial_count -1)); $factor >= 1; --factor ))
do
factorial_count=$(($factorial_count * $factor))
done
echo $factorial_count
}
prime_number () {
local prime=$1
p_minus_1=$(($prime - 1))
fact_p_minus_1=`factorial "$p_minus_1"`
fact_plus_1=$(($fact_p_minus_1 + 1))
echo $fact_plus_1
}
highest_number=$1
if [ -z $highest_number ]
then
echo
echo "Usage: $0 highestNumber"
echo
exit 1
fi
if [ $highest_number -eq 0 ]
then
echo
echo "Sorry. 0 is not a prime number"
echo
exit 0
elif [ $highest_number -eq 1 ]
then
echo
echo "Sorry. 0 and 1 are not prime numbers"
echo
exit 0
fi
echo "Generating Prime Numbers Up To $highest_number"
if [ $highest_number -eq 2 ]
then
echo
echo -n "2"
else
echo
echo -n "2 3 "
fi
count=4
while [ $count -le $highest_number ]
do
prime_return=`prime_number "$count"`
prime_test=$(($prime_return % count))
if [ $prime_test -eq 0 ]
then
echo -n "$count "
fi
count=$(($count + 1))
done
echo
echo
echo "All Set!"
echo
exit 0
Related
I'm using cURL to get some data from a website, so how to do to execute a command if two parameters from this website is the same for 5 minutes?
#!/bin/bash
TIME= "300s"
abc=`$CURL ***
abcd=`$CURL ***
echo $abc
echo $abcd
if [ [ [ "$abc" -eq "eee" || "$abc" -eq "rrr" ] || [ "$abcd" -eq "eee" || "$abcd" -eq "rrr" ] ] -ge [ "$TIME" ] ]
then
echo "Critical hosts: "$abc
echo "Critical service: "$abcd
fi
So if $abc and $abcd are == "eee" or == "rrr" for 5 minutes then do the command.
Below the skeleton to your script. You will have to implement my_curl_function yourself, but I suggest to call the curl function once and parse the data for both SERVER and SERVICE. Calling it once for each variable brings a lot of overhead, which causes the loop not to be exactly 5 minutes (which it isn't already). If you really, really, really want it to be exactly 5 minutes, use Python ;-)
The script validates every second whether the content of SERVER or SERVICE is changed. If either one of them are different than what's expected, the loop will break and the script echoes "Data is changed". It will echo "Data remains unchanged" otherwise.
#! /bin/bash
function my_curl_function {
echo "Implement me!"
}
MYTIME=300
SERVER_EXPECTED=$(my_curl_function)
SERVICE_EXPECTED=$(my_curl_function)
SERVER=""
SERVICE=""
CHANGED=0
for ((x=0; x<MYTIME;x++)); do
SERVER=$(my_curl_function)
SERVICE=$(my_curl_function)
if [ "${SERVER_EXPECTED}" != "${SERVER}" ] || [ "${SERVICE_EXPECTED}" != "${SERVICE}" ]; then
CHANGED=1
break
fi
echo -ne "\rSeconds waiting: $x"
sleep 1
done
echo
if [ ${CHANGED} -eq 1 ]; then
echo "Data is changed"
exit 0
else
echo "Data remains unchanged"
exit 1
fi
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"
I am trying to write a bash script to find if a number is prime, but i can't find what is wrong with my script
#!/bin/bash
#set -x
echo -n "enter a number "
read isPrime
count=2
x=0
while [ $count -lt $isPrime ]; do
if [ `expr $isPrime % $count`-eq 0 ]; then
echo "not prime"
fi
count=`expr $count + 1`
done
echo " it is prime"
#set +x
Using factor would be easy. But if you somehow need a script, I would implement something like following. I'm not sure whether this is the best algorithm, but this is way efficient than yours.
function is_prime(){
if [[ $1 -eq 2 ]] || [[ $1 -eq 3 ]]; then
return 1 # prime
fi
if [[ $(($1 % 2)) -eq 0 ]] || [[ $(($1 % 3)) -eq 0 ]]; then
return 0 # not a prime
fi
i=5; w=2
while [[ $((i * i)) -le $1 ]]; do
if [[ $(($1 % i)) -eq 0 ]]; then
return 0 # not a prime
fi
i=$((i + w))
w=$((6 - w))
done
return 1 # prime
}
# sample usage
is_prime 7
if [[ $? -eq 0 ]]; then
echo "not a prime"
else
echo "it's a prime"
fi
You can find an explanation about the used algorithm here
I have a script to write that is able to take user input of however many numbers they want until they press "q". Now I have it working, but it takes q and uses it in the math that the other numbers should be being used in. It also uses it to show what is the highest or lowest number.
total=0
count=0
largest=num
smallest=num
while [ "$num" != "q"
do
echo "Enter your numbers when you are done enter q"
read num
total=`expr $total + $sum`
count=`expr $count + 1`
if [ "$num" > "$largest" ]
then
largest=$num
fi
if [ "$num" < "$smallest" ]
then
smallest=$num
fi
done
avg=`expr $total / $count`
echo "The largest number is: $largest"
echo "The smallest number is: $smallest"
echo "The sum of the numbers is: $total"
echo "The average of the numbers is: $avg"
You aren't checking if the first value of num is "q" before attempting to use it as a number. The easiest thing to do is write an "infinite" loop with an explicit break; this avoids needing two separate read commands.
> and < are for string comparisons (and need to be escaped when used with [); use -gt and -lt instead.
You also do not need to use expr for integer arithmetic. For the average, you'll need to use bc (or some other program that can do floating-point arithmetic).
total=0
count=0
largest=
smallest=
while : ; do
echo "Enter your numbers when you are done enter q"
read num
[ "$num" = q ] && break
total=$(($total + $sum))
count=$(($count + 1))
if [ -z "$largest" ] || [ "$num" -gt "$largest" ]; then
largest=$num
fi
if [ -z "$smallest" ] || [ "$num" < "$smallest" ]; then
smallest=$num
fi
done
# Avoid division by 0 and meaningless statistics if
# no numbers are entered.
if [ "$count" -gt 0 ]; then
avg=$( echo "$total / $count" | bc )
echo "The largest number is: $largest"
echo "The smallest number is: $smallest"
echo "The sum of the numbers is: $total"
echo "The average of the numbers is: $avg"
fi
total=0
count=0
largest=num
smallest=num
echo "Enter your numbers when you are done enter q"
read num
while [ "$num" != "q"
do
total=`expr $total + $sum`
count=`expr $count + 1`
if [ "$num" > "$largest" ]
then
largest=$num
fi
if [ "$num" < "$smallest" ]
then
smallest=$num
fi
echo "Enter your numbers when you are done enter q"
read num
done
avg=`expr $total / $count`
echo "The largest number is: $largest"
echo "The smallest number is: $smallest"
echo "The sum of the numbers is: $total"
echo "The average of the numbers is: $avg"
I have a simple script in Bash to read a number in a file and then compare it with a different threshold. The output is this:
: integer expression expected
: integer expression expected
OK: 3
My code is this:
#!/bin/bash
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(cat /tmp/wget.txt | awk 'NR==6')
#output=7
echo $output
if [ $output -ge 11 ];then
echo "CRITICAL: $output"
exit 2
elif [ $output -ge 6 ] && [ $output -lt 11 ];then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi
rm /tmp/wget.txt
I know what is the problem, I know that I'm reading a string and I try to compare a int. But I don't know how can I do to read this file and convert the number to read in a int var..
Any ideas?
The problem occurs when $output is the empty string; whether or not you quote the expansion (and you should), you'll get the integer expression required error. You need to handle the empty string explictly, with a default value of zero (or whatever default makes sense).
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(awk 'NR==6' < /tmp/get.txt)
output=${output:-0}
if [ "$output" -ge 11 ];then
echo "CRITICAL: $output"
exit 2
elif [ "$output" -ge 6 ];then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi
(If you reach the elif, you already know the value of $output is less than 11; there's no need to check again.)
The problem also occurs, and is consistent with the error message, if output ends with a carriage return. You can remove that with
output=${output%$'\r'}
There are a couple of suggestions from my side regarding your code.
You could explicitly tell bash the output is an integer
declare -i output # See [1]
Change
output=$(cat /tmp/wget.txt | awk 'NR==6') # See [2]
may be better written as
output=$(awk 'NR==6' /tmp/wget.txt )
Change
if [ $output -ge 11 ]
to
if [ "0$output" -ge 11 ] # See [4]
or
if (( output >= 11 )) # Better See [3]
References
Check bash [ declare ].
Useless use of cat. Check [ this ]
Quoting [ this ] answer :
((...)) enable you to omit the dollar signs on integer and array variables and include spaces around operators for readability. Also empty variable automatically defaults to 0 in such a statement.
The zero in the beginning of "0$output" help you deal with empty $output
Interesting
Useless use of cat is a phrase that has been resounding in SO for long. Check [ this ]
[ #chepner ] has dealt with the empty output fiasco using [ bash parameter expansion ] in his [ answer ], worth having a look at.
A simplified script:
#!/bin/bash
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(awk 'NR==6' </tmp/wget.txt )
output="$(( 10#${output//[^0-9]} + 0 ))"
(( output >= 11 )) && { echo "CRITICAL: $output"; exit 2; }
(( output >= 6 )) && { echo "WARNING: $output"; exit 1; }
echo "OK: $output"
The key line to cleanup any input is:
output="$(( 10#${output//[^0-9]} + 0 ))"
${output//[^0-9]} Will leave only digits from 0 to 9 (will remove all non-numeric chars).
10#${output//[^0-9]} Will convert output to a base 10 number.
That will correctly convert numbers like 0019
"$(( 10#${output//[^0-9]} + 0 ))" Will produce a zero for a missing value.
Then the resulting number stored in output will be compared to limits and the corresponding output will be printed.
In BASH, It is a good idea to use double brackets for strings:
if [[ testing strings ]]; then
<whatever>
else
<whatever>
fi
Or double parenthesis for integers:
if (( testing ints )); then
<whatever>
else
<whatever>
fi
For example try this:
var1="foo bar"
if [ $var1 == 'foo bar' ]; then
echo "ok"
fi
Result:
$ bash: [: too many arguments
Now, this:
var2="foo bar"
if [[ $a == "foo bar" ]]; then
echo "ok"
fi
Result:
ok
For that, your code in BASH:
if [[ $output -ge 11 ]]; then
echo "CRITICAL: $output"
exit 2
elif [[ $output -ge 6 ]]; then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi