问题描述:

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

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
```

& 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.

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.

`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).

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
```