tags:

views:

97

answers:

5

I'm curious about what exactly the following comparison does, in as much detail as possible, especially relating to the 0x2 and the & characters and what exactly they do,

if [ $((${nValid} & 0x1)) -eq 1 ]; then
  #...snip...
fi

if [ $((${nValid} & 0x2)) -eq 2 ]; then
  #...snip...
fi
+3  A: 

& is the bitwise AND operator. So you are asking to do a bitwise and between 0x1 and the value that ${nVAlid} is returning.

For more information on bitwise operations look here.

dave
+3  A: 

A shell script interprets a number as decimal (base 10), unless that number has a special prefix or notation. A number preceded by a 0 is octal (base 8). A number preceded by 0x is hexadecimal (base 16). A number with an embedded # evaluates as BASE#NUMBER (with range and notational restrictions).

So, in [ $((${nValid} & 0x1)) -eq 1 ], $nValid is anded with 0x1 and compared with decimal 1. Similarly the second comparison too.

Read this and this for detailed info.

pavanlimo
Can you describe what happens when "`$nValid` is anded with `0x1`"?
tj111
@tj111: See these links:http://en.wikipedia.org/wiki/Binary_andhttp://en.wikipedia.org/wiki/Bitwise_operation
DarkDust
pavanlimo
+2  A: 

0x1 and 0x2 are the hexadecimal notations for 1 and 2. The & is the bitwise AND operator. What these lines do is test the value in nValid whether the least significant bit (0x1) and second least significant bit (0x2) are set.

The scheme goes like this (C notation):

if (val & (1 << bitNumber) == (1 << bitNumber)) {
  // The bit at position bitNumber (from least to most significant digit) is set
}

The << is the left bitshift operator. 1 << 0 == 1, 1 << 1 == 2, 1 << 2 == 4, ...

So for better readability the lines should be more like:

if [ $((${nValid} & X)) -eq X ]; then

where X is a power of 2 (instead of mixing hexadecimal and decimal notation).

DarkDust
+2  A: 

It's testing nValid on a per-bit basis.

The bitwise AND operator (&) means that bit-by-bit, the operator will do an AND comparison. So, if nValid is a byte (8 bit) value, then look at the operation in binary:

nValue & 0b00000001

If nValue is 42, then the operation would look like this

(nValue = 0b00101010) & 0b00000001 => 0b00000000 // (does not have the last bit set)
(nValue & 0b00000001) == 0b00000001 // false

and for the 2nd (nValid & 0x2)

(nValue = 0b00101010) & 0b00000010 => 0b00000010 // (has the 2nd-to-last bit set)
(nValue & 0b00000010) == 0b00000010 // true

This is useful for testing flags within variables; usually you use the AND to check for flags by isolating bits and the OR to combine flags.

0b00001000 | 0b00000010 | 0b00000001 => 0b00001011
palswim
+2  A: 

That could be rewritten as:

if (( nValid & 2#00000001 )); then
  #...snip...
fi

if (( nValid & 2#00000010 )); then
  #...snip...
fi

with the number of binary digits chosen to be most appropriate for the context. It's not necessary to test for equality if you're only checking one bit*. You could still use the hex representation if it makes more sense. The braces and dollar sign aren't necessary in this context.

You might want to use constants with meaningful names instead of hard-coded values:

declare -r FOO=$((2#00000001))
declare -r BAR=$((2#00000010))
if (( nValid & FOO )); then
  #...snip...
fi
if (( nValid & BAR )); then
  #...snip...
fi

* You will need to test for equality if you're testing multiple bits at the same time:

if (( (nValid & (FOO | BAR)) == (FOO | BAR) )); then
  #...snip...
fi

You will need the extra parentheses since == has a higher precedence than the bitwise operators.

Clearing and setting bits in Bash:

(( var |= FOO ))    # set the bits in FOO into var
(( var &= ~BAR ))   # clear the bits in BAR from var
Dennis Williamson