Bash parse list for prime numbers. - bash

I want to parse a list of hexas that i get from a file after parsing them for unique hexas and sorting them.
The list looks like this:
1 0xb6e38000
8 0xb6f66000
5 0xb6f69000
1 0xb6f6c000
3 0xb6fd4000
1 0xb6ff7000
2 0xb6ff8000
4 0xb6ffa000
1 0xb6ffb000
Now what i want to do, is refine it even more so that i get only the hexas with prime numbers in front, like this:
1 0xb6e38000
5 0xb6f69000
1 0xb6f6c000
3 0xb6fd4000
1 0xb6ff7000
1 0xb6ffb000
The command i have been using is this:
sort | uniq -c | grep " 1 0x"
But this command lists only the ones that appear only once in the file.
Can anyone help me "sort" this out ?

Original answer for prime numbers
As mentioned in the comments to the question, 1 is not prime, but in the description of desired output you list the lines starting with 1. However, if you actually want to filter out the lines with prime numbers in the first column, then the following script will help:
#!/bin/bash -
[ $# -gt 0 ] && source_file="$1"
: ${source_file:=/tmp/source-file}
function is_prime {
declare -i n="$1"
if [ $n -le 1 ]; then
return 1
elif [ $n -le 3 ]; then
return 0
elif [[ $(( $n % 2 )) == 0 || $(( $n % 3 )) == 0 ]]; then
return 1
fi
i=5
while [[ $(( $i * $i )) -le $n ]]; do
if [[ $(( $n % $i )) == 0 || $(( $n % ($i + 2) )) == 0 ]]; then
return 1
fi
(( i += 6 ))
done
return 0
}
while read -a line; do
# We accept only two or more columns
[ ${#line[#]} -ge 2 ] || continue;
if is_prime ${line[0]}; then
echo $line
else
echo >&2 "skipping ${line[*]} as ${line[0]} is not prime"
fi
done < "$source_file"
In this script we define is_prime function which returns zero (success status), if the first argument ($1) is a prime number. Non-zero means non-prime number. The algorithm is a version of this pseudo-code translated into Bash.
Then we read $source_file line by line with the while loop where we put the columns into the line array: read -a line. Then we check if is_prime ${line[0]} command exits with a success code (zero) and output the line if it is. Otherwise, we print a message to the standard error (echo >&2).
The script accepts optional argument for the source file path. It assigns $source_file to /tmp/source-file, if the first argument is missing.
Script usage
Save the above-mentioned code in script.sh file.
Call bash script.sh /path/to/source-file >filtered 2>errors
Examine the contents of filtered and errors files. The first will contain the lines filtered out from the source file.
The output files will look like the following:
filtered
5 0xb6f69000
3 0xb6fd4000
2 0xb6ff8000
errors
skipping 1 0xb6e38000 as 1 is not prime
skipping 8 0xb6f66000 as 8 is not prime
skipping 1 0xb6f6c000 as 1 is not prime
skipping 1 0xb6ff7000 as 1 is not prime
skipping 4 0xb6ffa000 as 4 is not prime
skipping 1 0xb6ffb000 as 1 is not prime
Update for odd numbers
i sould have mentioned this from the start, i need odd number lines to
show up, not prime. My bad. – biotic
It's easy to detect if a number is odd with an expression like if [[ $(( $n % 2 )) != 0 ]]. The expression checks if the remainder by 2 is not equal to zero, i.e. applies the modulo operation. If the remainder is zero, then the number is even, otherwise odd, of course.
The full script:
#!/bin/bash -
[ $# -gt 0 ] && source_file="$1"
: ${source_file:=/tmp/source-file}
while read -a line; do
# We accept only two or more columns
[ ${#line[#]} -ge 2 ] || continue;
declare -i n=${line[0]}
if [[ $(( $n % 2 )) != 0 ]]; then
echo ${line[*]}
else
echo >&2 "skipping ${line[*]} as ${line[0]} is even"
fi
done < "$source_file"
As for above, you run bash script.sh /path/to/source-file >filtered 2>errors
Sample output:
filtered
1 0xb6e38000
5 0xb6f69000
1 0xb6f6c000
3 0xb6fd4000
1 0xb6ff7000
1 0xb6ffb000
errors
skipping 8 0xb6f66000 as 8 is even
skipping 2 0xb6ff8000 as 2 is even
skipping 4 0xb6ffa000 as 4 is even

Related

How to use if then in bash

We have a text file with 4 lines and a different number of words and i want to count the words per line and see if the number is even or odd but the result keeps saying
./oddwords.sh: line 14: syntax error near unexpected token `then'
./oddwords.sh: line 14: ` if[ n % 2 == 0 ]; then'
This is what ive done so far
#!/bin/bash
if [ $# -ne 1 ] ; then
{
echo "Wrong number of arguments!"
exit 1
}
fi
while read line ; do
n= echo "$(echo $line | wc -w)"
if[ n % 2 == 0 ]; then
echo "Is even"
else
echo "Is odd"
fi
done < $1
Using double brackets like
if [[ n % 2 == 0 ]]; then
and making the numbers variables at the top instead of just saying 2
a=2
b=1
at the beginning then referencing them later in the if statement like
if [[ $a%2 == 0 ]]; then
if you still have issues try
if [[ $a%2 -eq 0 ]]; then
Here are a couple sites i find useful for checking bash when I get stuck on something as well.
https://www.shellcheck.net/
https://explainshell.com/

storing the contents or a for loop into an array and then retrieving it for if statements

I'm having a bit of trouble, id like to store the contents of the values from my for loop into an array or something and then recall these values to be tested against the if statements and then printed accordingly. My current code gives me a good output however if I use large numbers like 1 and 50 as input values it gives me multiple rows of "Divisible by xValue" instead of just one of each value. Thanks in advance
if (( $# > 2 )); then
echo "Only your first two values will be used"
for((i=($1+($1%2));i<($2-3);i+=2));do #for loop lists all even numbers between two input values
if (( i % 7 == 0 )); then #checks if even number divisible by 7
echo " $i : Divisible by 7 " # prints number and labels
elif (( $i % 11 == 0 )); then #else if checks if divisible by 7
echo " $i : Divisible by 11 " #prints number and labels
elif (( $i % 13 == 0 )); then #if divisible by 13
echo " $i : Divisible by 13 "
fi #closes the if statement
printf "%d%s, " "$i"
done
echo "$i"
Use +=() in bash to add a new element into an array.
#! /bin/bash
set -eu
if (( $# > 2 )); then
echo "Only your first two values will be used"
fi
even=()
for ((i=$1; i<=$2; ++i)) ; do
if (( i % 2 == 0 )) ; then
even+=($i)
fi
done
for e in "${even[#]}" ; do
for d in 7 11 13 ; do
if (( e % d == 0 )); then
echo "$e: Divisible by $d"
break
fi
done
printf "%d%s, " "$e"
done

prime number function in shell script

I am new to Shell script. I have written a function to check weather a number is prime or not but I am getting error of Unary operator expected in if condition. Kindly point out where I have done mistake.
file :fprime.sh
prime ()
{
n=$1
t=0
for i in {2..$n}
do
r=`expr $n % $i`
if [ $r == 0 ]
then
t=`expr t + 1`
fi
done
if [ $t == 1 ]
then
echo "prime"
else
echo "not prime"
fi
}
prime
Output:
~$ ./fprime.sh 5
expr: syntax error
./fprime.sh: line 8: [: ==: unary operator expected
not prime
Try changing, 3 places there are other syntax error too,
1) if [ $r == 0 ]
// to
if [ $r -eq 0 ]
2) t=`expr t + 1`
// to
t=`expr $t + 1`
3) if [ $t == 1 ]
// to
if [ $t -eq 1 ]
Notes
1) and 3) , -eq is used to equate integers in bash == is to equate String/charactor(s)
2) - missed $ symbol for variable t
Also, just to point out, you can directly use the $1 without assigning to variable n again
The following function will return 0 (no error --> true) if the number is prime.
The function will return 1 (error --> false) if the number is not prime.
For those who never saw it before, REMAINDER_S is an array (in which every reminder of the division, different from zero, is stored).
As prime numbers are divisible only by themselves (and 1 of course), in the moment a division provides a reminder equals to zero, the number will not be prime.
Otherwise (none of the reminders is zero), the array REMINDER_S will be empty and the number will be a prime number.
Do not forget to use "break" in the first "if" statement, if you intend to substitute the "return 1" for some echo message.
is_prime () {
declare -a REMAINDER_S=()
let ARG_1=$1-1
for N in $(seq 2 $ARG_1)
do
let REMINDER=$1%$N
if [ $REMINDER == 0 ]
then
REMINDER_S=("${REMINDER_S[#]}" $REMINDER)
return 1
fi
done
if [ ${#REMINDER_S[#]} == 0 ]
then
return 0
fi
}
A simple code :
function prime()
{
for((i=2; i<=num; i++))
do
if [ `expr $num % $i` == 0 ]
then
echo $num is not prime
exit
fi
done
echo $num is a prime number
}
read num;
prime "$num";

What is this Bash Syntax in FizzBuzz Example

I just found the following FizzBuzz example on Hacker News and it uses a piece of syntax I'm finding it difficult to search for
for num in {1..100} ; do
out=""
(( $num % 3 == 0 )) && out="Fizz"
(( $num % 5 == 0 )) && out="${out}Buzz"
echo ${out:-$num}
done
The bit I don't understand is how the variable usage works in the echo line. Though I can obviously see that it becomes $out if not empty, else $num
for num in {1..100} ; do
Loop from 1 to 100.Set num to each integer on the way
out=""
Set out to nothing
(( $num % 3 == 0 )) && out="Fizz"
If the number is divisible by 3 set out to Fizz
(( $num % 5 == 0 )) && out="${out}Buzz"
If the number is divisible by 5 set out to whatever is contained in out then Buzz.
echo ${out:-$num}
Uses parameter substitution to check that out contains something, if it does not, then use num instead.
Echos result of the substitution.
done
Resources
http://tldp.org/LDP/abs/html/parameter-substitution.html - parameter substitution
http://tldp.org/LDP/abs/html/ops.html - let command ((...))
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html - loops

Converting from for loop to while if fi loop UNIX

I'm trying to figure out how to convert the following for loop into a while loop or until loop including if fi for UNIX Here's the code...
#!/bin/bash
if [ $# -gt 0 ] ; then
start=$1
end=$3
step=$2
for x in `seq $start $step $end` ; do
number $x
done
else
echo Enter at least one number on the command line.
fi
Any help is greatly appreciated!
(( x = start ))
until (( x > end ))
do
number $x
(( x += step ))
done
For a loop like this, it's easiest to use the numeric-style for loop:
for ((x=start; x<=end; x+=step)); do
number $x
done
Using seq is good as it has some default values for step and end value. I added this to the if if only one, or two arguments are given. Also it handles the situation if the given argument are not numbers (default values are 0). Also an endless loop may encounter if step is zero. If You remove this checking it will work the same way as the seq version.
if [ $# -gt 0 ] ; then
x=$(($1+0))
end=$((${3:-$x}+0))
step=$((${2:-1}+0))
[ $step -eq 0 ] && echo "Step is zero!" && exit 1
while [ $x -le $end -a $step -gt 0 -o $x -ge $end -a $step -lt 0 ]; do
echo $x
x=$((x+step))
done
else
echo Enter at least one number on the command line.
fi
Change echo to number in the while loop if you would like to use!
Examples:
$ ./e.sh 1
1
$ seq 1
1
$ ./e.sh 1 1 3
1
2
3
$ seq 1 1 3
1
2
3
$ ./e.sh 1 -1 3
$ seq 1 -1 3
$ ./e.sh 3 -1 1
3
2
1
$ seq 3 -1 1
3
2
1
$ ./e.sh 1 0 1
Step is zero!
$ seq 1 0 1|head
1
1
1
... (endlessly)
$ ./e.sh 1 .1 1.2
./e.sh: line 3: 1.2+0: syntax error: invalid arithmetic operator (error token is ".2+0")
$ seq 1 .1 1.2
1.0
1.1
1.2
Bash arithmetic is not working with floating point numbers, but seq does. If You need this feature You could use the x=$(echo $x + $step|bc) format. Also $((...)) should replaced by $(...|bc) like lines.
In Bash 4 you can also do it like this:
for i in {$start..$stop..$step}; do
echo $i
done

Resources