Removing leading zeros before passing a shell variable to another command

It turns out that iptables doesn't handle leading zeros too well. As $machinenumber that is used has to have a leading zero in it for other purposes, the idea is simply to create a new variable ($nozero) based on $machinenumber, where leading zeros are stripped away.

$machinenumber is a two-digit number between 01 and 24. Currently it's 09

$machinetype is 74 for now and hasn't caused any problems before.

What I have so far is:

nozero = (echo $machinenumber | sed 's/^0*//')
iptables -t nat -I POSTROUTING -s 10.($machinetype).($nozero).0/24 -j MASQUERADE

While I believe I'm on the right track, the code results in:

ERROR - Unknown string operation

Solution 1:

You don't need to use sed or another external utility. Here are a couple of ways Bash can strip the leading zeros for you.

iptables -t nat -I POSTROUTING -s "10.$machinetype.$((10#$machinenumber)).0/24" -j MASQUERADE

The $(()) sets up an arithmetic context and the 10# converts the number from base 10 to base 10 causing any leading zeros to be dropped.

shopt -s extglob
iptables -t nat -I POSTROUTING -s "10.$machinetype.${machinenumber##+(0)}.0/24" -j MASQUERADE

When extglob is turned on, the parameter expansion shown removes all leading zeros. Unfortunately, if the original value is 0, the result is a null string.

Solution 2:

No, you make all (alomost all) correct. You just must:

  • remove spaces around =
  • use $() or backticks instead of ()

That would be correct:

 nozero=$(echo $machinenumber | sed 's/^0*//')

Also you must use variables without () around them. You can add "" if you want:

iptables -t nat -I POSTROUTING -s "10.$machinetype.$nozero.0/24" -j MASQUERADE

And of course variables here are not necessary. You can say simply:

iptables -t nat -I POSTROUTING -s "10.$(echo $machinenumber | sed 's/^0*//').$nozero.0/24" -j MASQUERADE

Solution 3:

you can also do

machinenumber=$(expr $machinenumber + 0)

Solution 4:

I can't comment as I don't have sufficient reputation, but I would suggest you accept Dennis's answer (which is really quite neat)

Firstly, I don't think that your answer is valid bash. In my install I get:

> machinetype=74
> machinenumber=05
> iptables -t nat -I POSTROUTING -s 10.($machinetype).($machinenumber + 0).0/24 -j MASQUERADE
-bash: syntax error near unexpected token `('
> echo 10.($machinetype).($machinenumber + 0).0/24
-bash: syntax error near unexpected token `('

If I quote it I get:

> echo "($machinetype).($machinenumber + 0)"
(74).(05 + 0)

I'm assuming you mean:

> echo 10.$(($machinetype)).$(($machinenumber + 0)).0/24
10.74.5.0/24

But, of course it's still a bad solution because of octal:

> machinenumber=09
> echo 10.$(($machinetype)).$(($machinenumber + 0)).0/24
-bash: 09: value too great for base (error token is "09")

I assume that your numbers aren't 08 or 09 at the moment.

Here's Dennis's:

> echo $((10#09))
9
> echo $((10#00))
0
> echo $((10#00005))
5
> echo $((10#))
0

Admittedly, that last one might be an input validation problem for someone.

The sed solution has the problem of:

> echo "0" | sed 's/^0*//'

>

Solution 5:

nozero=$(echo $machinenumber | sed 's/^0*//')

Try without the spaces around = and with an additional $ sign.