How do I make this bitwise code more concise? - bash

My bitwise code which works is:
#!/bin/bash -e
random=$((RANDOM % 32));
bitWiseAnd() {
local IFS='&'
printf "%s\n" "$(( $* ))"
}
echo "random=${random}";
if [ $(bitWiseAnd ${random} "0x10") -ne 0 ]; then
echo "1"
else
echo "0"
fi
if [ $(bitWiseAnd ${random} "0x8") -ne 0 ]; then
echo "1"
else
echo "0"
fi
if [ $(bitWiseAnd ${random} "0x4") -ne 0 ]; then
echo "1"
else
echo "0"
fi
if [ $(bitWiseAnd ${random} "0x2") -ne 0 ]; then
echo "1"
else
echo "0"
fi
if [ $(bitWiseAnd ${random} "0x1") -ne 0 ]; then
echo "1"
else
echo "0"
fi
A sample output from the above code:
random=15
0
1
1
1
1
I have no idea how this code works. Can this code be made more concise?

You could use a for loop instead of repeated if blocks. Also, the for loop spells out your purpose more clearly, like this:
#!/bin/bash -e
bitWiseAnd() {
local IFS='&'
printf "%s\n" "$(( $* ))"
}
random=$((RANDOM % 32));
echo "random=${random}";
for i in 10 8 4 2 1; do
if [ $(bitWiseAnd ${random} "0x$i") -ne 0 ]; then
echo "1"
else
echo "0"
fi
done
Output:
random=10
0
1
0
1
0
Also, the function below
bitWiseAnd() {
local IFS='&'
printf "%s\n" "$(( $* ))"
}
could be made more explicit this way, as long as we are looking at just two input arguments:
bitWiseAnd() {
printf "%s\n" $(($1 & $2))
}

This won't produce the exact same output as you need, because you asked for an optimization and it doesn't involve multiple useless echo statements.
Another approach would be using a while-loop and check if bit-positions are still valid. I have removed the useless echo statements, assuming you don't need any of that and just want to improve the code.
bitMask="0x10"
while [ $(bitWiseAnd "31" "$bitMask") -ne 0 ] && ((bitMask))
do
bitMask=$((bitMask >> 1))
done
Just replace the hard-coded number 31 with the variable value $random and bitMask of your choice.

Related

script8.sh: line 9: [: missing `]' [duplicate]

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 3 years ago.
I'm trying to do test automation with a bash script using if then else statements but I'm running into a few errors. For one, when I try to execute it I'm doing something wrong with the variable assignment with j and k, because it tells me that the command j and the command k aren't found when I try to execute. How do you correctly create variables?
The most confusing thing though is when I try to execute the script I get an error telling me I have an unexpected token near fi, and then it just says 'fi'. What am I doing wrong here?
#!/bin/bash
j = 0
k = 0
echo Test1:
echo -ne "0\nIn\nUG\n" | /u/cgi_web/Tuition/cost
echo Test2:
echo -ne "0\nOut\nUG\n" | /u/cgi_web/Tuition/cost
echo Test3:
echo -ne "0\nIn\nGR\n" | /u/cgi_web/Tuition/cost
echo Test4:
echo -ne "0\nOut\nGR\n" | /u/cgi_web/Tuition/cost
for i in {1..17}
do
echo Test$((i+4)):
if[ "$j" -eq 0 ] && [ "$k" -eq 0 ] then
$j = 1
echo -ne "$i\nIn\nUG\n" | /u/cgi_web/Tuition/cost
elif[ "$j" -eq 1 ] && [ "$k" -eq 0 ] then
$k = 1
echo -ne "$i\nIn\nGR\n" | /u/cgi_web/Tuition/cost
elif[ "$j" -eq 1 ] && [ "$k" -eq 1 ] then
$j = 0
echo -ne "$i\nOut\nUG\n" | /u/cgi_web/Tuition/cost
elif[ "$j" -eq 0 ] && [ "$k" -eq 1 ] then
$k = 0
echo -ne "$i\nOut\nGR\n" | /u/cgi_web/Tuition/cost
fi
done
EDIT: I figure out the variable issue with j and k, I had to remove the spaces in the statement.
Bash if statements require a semi-colon before the then:
if [ condition ] || [ condition ]; then
# code
elif [ condition ] && [ condition ]; then
# code
fi
For example.
To help anyone who might look at this for help in the future, I figured I'd answer my own question with all the syntax errors I found from my own testing and with the helpful responses of others.
To start the variable assignment:
j = 0
you can't have spaces in between, so it would be:
j=0
Also if statements need a space between if and the bracket and need a semicolon after the last bracket before then. Therefore my incorrect if statement
if[ "$j" -eq 0 ] && [ "$k" -eq 0 ] then
becomes
if [ "$j" -eq 0 ] && [ "$k" -eq 0 ]; then
or instead of a semicolon you can have a new line between the bracket, so it would become
if [ "$j" -eq 0 ] && [ "$k" -eq 0 ]
then

How to write if else in one line in shell?

I would like to write in one line this:
if [$SERVICESTATEID$ -eq 2]; then echo "CRITICAL"; else echo "OK"; fi
So to do a test in my shell I did:
if [2 -eq 3]; then echo "CRITICAL"; else echo "OK"; fi
The result is
-bash: [2: command not found
OK
So it doesn't work.
Space -- the final frontier. This works:
if [ $SERVICESTATEID -eq 2 ]; then echo "CRITICAL"; else echo "OK"; fi
Note spaces after [ and before ] -- [ is a command name! And I removed an extra $ at the end of $SERVICESTATEID.
An alternative is to spell out test. Then you don't need the final ], which is what I prefer:
if test $SERVICESTATEID -eq 2; then echo "CRITICAL"; else echo "OK"; fi
Write like this, space is required before and after [ and ] in shell
if [ 2 -eq 3 ]; then echo "CRITICAL"; else echo "OK"; fi
Shorter format.
( [ 2 -eq 3 ] && echo "CRITICAL" ) || echo "OK"
Regex pattern type numbers : 10,12.1,+3.33,-1,0004,-48.9
Oneliner attacks again!
( [ `echo $number 2>/dev/null | grep -E "^[ ]*(\+|\-){0,1}[0-9]+(\.[0-9]+)?$"` ] && echo "NUMBER" ) || echo "NOT NUMBER"

[: : integer expression expected

COUNTER=0
let COUNTER=COUNTER+1
count=`ssh -i /var/www/.ssh/id_rsa_root -o stricthostkeychecking=no $host $cmd`
count1=`echo $count | awk '{print $4}'`
printf "count1 : $count1\n"
result1=${count1/.*}
if [ "$result1" -ge "0" ]; then
echo $host
else
echo $host
exit
fi
If the value of $result1 is INTEGER and greater than zero, it'll goto IF loop (works fine for me)
But when it is not INTEGER, it is coming to else loop (which it is suppose to do) with the following error in the Output
line 55: [: : integer expression expected
but i dont want the above error in my output. I tried to use 2>/dev/null with this but no luck.
please help!
If you want to handle an empty result gracefully, check for it explicitly:
if [ -z "$result1" ]; then
: "ignoring empty string"
elif [ "$result1" -ge 0 ]; then
printf '%s\n' "$host"
else
printf '%s\n' "$host"
exit
fi
You could also check if result1 is a valid integer before making arithmetic comparisons:
function isNumber () {
[[ $1 =~ ^-?[0-9]+$ ]]
}
if ! isNumber "$result1"; then
echo "not a number"
elif [ "$result1" -ge "0" ]; then
echo "null or positive"
else
echo "negative"
fi
Change if [ "$result1" -ge "0" ]; then to
if (( result1 >= 0 )); then
This syntax won't throw any errors if result1 isn't defined (or empty) or happen to be a string somehow.

Bash; conditional statement echoing numbers

I'm nearly done writing a script for an assignment, but am having some trouble thinking of how to do this final part.
My problem is within a while loop; it prints out the number based on the IF statements, the number entered will always be an even number.
The IFs aren't connected by else/elif because the number should be able to printed out if it applies to more than 1 of the statements.
I want to print $starting on every loop if it doesn't meet any of the IF conditions, but if it does I don't want to print it. Can anyone see how to do that?
while [[ $starting -lt $ending ]]; do
if [ $((starting %7)) -eq 0 ]
then
echo "$starting red"
fi
if [ $((starting % 11)) -eq 0 ]
then
echo "$starting green"
fi
if [ $((starting % 13)) -eq 0 ]
then
echo "$starting blue"
fi
starting=$((starting + 2))
done
Keep track of whether you've done what you want to do in a variable:
while [[ $starting -lt $ending ]]; do
handled=0
if [ $((starting %7)) -eq 0 ]
then
echo "$starting red"
handled=1
fi
if [ $((starting % 11)) -eq 0 ]
then
echo "$starting green"
handled=1
fi
if [ $((starting % 13)) -eq 0 ]
then
echo "$starting blue"
handled=1
fi
if ! (( handled ))
then
echo "$starting didn't match anything"
fi
starting=$((starting + 2))
done
Add another if at the end that checks if none of the previous if statements are true. if !(starting%7==0 or starting%11==0 or starting%13==0) => echo starting

If statement with two or more conditions

I was modifying an script didn't know how to write more than one condition in an if statement. I want to connect the two condition with an AND.
if [ envoi1 -eq 2 ];then
if [ envoi2 -eq 0 ];then
echo 'Ahora mismo.'
envoi = 1
fi
else
if [ envoi2 -eq 1 ];then
if [ envoi1 -eq 1 ];then
echo 'Situacion Normal.'
envoi = 1
fi
else
echo 'Raruno'
envoi=`expr $envoi1 + envoi2`
fi
fi
Now i use nested if to do the same but the code it's not so clear for me.
try this:
if [ $envoi1 -eq 2 ] && [ $envoi2 -eq 0 ] ; then
envoi = 1
fi
In bash, you can use [[ as follows:
if [[ $envoi2 -eq 1 && $envoi1 -eq 1 ]]; then
echo "Situacion Normal."
envoi=1
fi
However, [[ is not POSIX and will not work if you are using the /bin/sh shell. So if portability is desired use:
if [ $envoi2 -eq 1 -a $envoi1 -eq 1 ]; then
echo "Situacion Normal."
envoi=1
fi
Also note that when assigning variables you should not have any spaces on either side of the =.

Resources