Reputation: 4353
OK, here's the code
printf "%0.s1" $(seq $1)
Simple enough, it sits in a function and you pass in a length and it gives you a bunch of 1s. This function then pads 0s to create a string of 32 bits which another function changes to an integer or IP. For example:
cdr2mask() {
local BIMASK=$(printf "%-32s" $(printf "%0.s1" $(seq $1)) | tr ' ' '0')
integerToIP $(convertbaseNumFromTo $BIMASK 2 10)
}
This function works fine when called directly (argument is the number of bits in your netmask, ex: 24). But, when called from the following, it fails. It gives a 1 followed by 31 0s instead of the correct mask. It gets $1 correctly. I've narrowed it down to the printf statement (the one at the top) only returning a single 1 when called this way. The function calling cdr2mask is:
ipInNetwork() {
local IFS HOST NETWORK NETMASK CIDR
read HOST NETWORK NETMASK <<<$*
if [ -z "$NETMASK" ]; then
IFS='/'
read NETWORK CIDR <<<"$NETWORK"
if [ -z "$CIDR" ]; then
NETMASK="255.255.255.255"
else
NETMASK=$( cdr2mask "$CIDR" )
fi
fi
if [ $(( $( ipToInteger $HOST ) & $( ipToInteger $NETMASK ) )) = \
$(( $( ipToInteger $NETWORK ) & $( ipToInteger $NETMASK ) )) ]; then
return 0;
else
return 1;
fi
}
The following versions of cdr2mask work fine, so its not the caller:
newcdr2mask() {
local ONES="11111111111111111111111111111111"
local BINUM=$(printf "%-32s" ${ONES:0:$1} | tr ' ' 0)
integerToIP $( convertbaseNumFromTo $BINUM 2 10 )
}
oldcdr2mask ()
{
# Number of args to shift, 255..255, first non-255 byte, zeroes
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
[ $1 -gt 1 ] && shift $1 || shift
echo ${1-0}.${2-0}.${3-0}.${4-0}
}
The last one I didn't write. Of course, suggestions on speed improvements and other suggestions are welcome. I'm not getting the speed I really want here, but I'm only just starting to optimize. The "old" method may still be the fastest, but I want to get the other version working so I can test it. Could this be a bash bug?
Upvotes: 1
Views: 214
Reputation: 206689
The culprit:
IFS='/'
This breaks the seq
expansion - seq
outputs newlines as separators (by default), and the shell doesn't do word splitting on those when IFS
is /
. (local IFS
doesn't help here, local variables are visible in the called functions.)
I'd avoid setting IFS entirely, by doing something like this instead of the read
:
CIDR=${NETWORK##*/}
NETWORK=${NETWORK%/*}
(With a case
statement to deal with the cases for NETWORK
containing a /
or not.)
Upvotes: 1