Removing leading zeros before passing a shell variable to another command

[亡魂溺海] 提交于 2019-11-28 06:45:01

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.

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

you can also do

machinenumber=$(expr $machinenumber + 0)
Duncan Irvine

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*//'

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

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

A pure bash solution:

> N=0001023450 
> [[ $N =~ "0*(.*)" ]] && N=${BASH_REMATCH[1]}
> echo $N 
1023450

Using sed:

echo 000498 | sed "s/^0*\([1-9]\)/\1/;s/^0*$/0/"
498
echo 000 | sed "s/^0*\([1-9]\)/\1/;s/^0*$/0/"
0
Cullen Fluffy Jennings

I do it by using

awk '{print $1 + 0}'

I like this better than the sed approach as it still works with numbers like 0, 000, and 001.

So in your example I would replace

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

with

nozero=$(echo $machinenumber | awk '{print $1 + 0}' )

I also can't comment or vote up yet, but the Duncan Irvine answer is the best.

I'd like to add a note about portability. The $((10#0009)) syntax is not portable. It works in bash and ksh, but not in dash:

$ echo $((10#09))
dash: 1: arithmetic expression: expecting EOF: "10#09"

$ dpkg -s dash | grep -i version
Version: 0.5.7-2ubuntu2

If portability is important to you, use the sed answer.

I would say you are very close. I do not see a requirement stated for bash, but your nonzero logic is flawed.

nonzero=`echo $machinenumber + 0 | bc`
iptables -t nat -I POSTROUTING -s 10.$machinetype.$nozero.0/24 -j MASQUERADE

Adding 0 is a common method for changing a string number into a non-padded integer. bc is a basic calculator. I use this method for removing space and zero padding from numbers all the time.

While I am not expert in iptables syntax, I am pretty sure the parenthesis are not necessary. Since I already have non-word characters bordering both variables, I do not need special enclosures around them. Word characters are;

[a-zA-z0-9_]

Using this solution, you do not lose zero as a potential value, and should be portable across all shells.

If you are using bash, this looks like the simplest:

nozero=$(bc<<<$machinenumber)

I had to revisit this code the other day due to some unrelated stuff, and due to compatibility with some other software that reads the same script, i found it a lot easiest to rewrite it into this, which should still be valid bash:

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

Basically, adding 0 forces it to be interpreted as an integer, hence automatically stripping the leading zeros

Add the number with 0, it will remove leading zeroes

eg: expr 00010 + 0 #becomes 10

OR

num=00076
num=${num##+(0)}
echo $num

If you don't have sed or awk or perl then you could use cut and grep

mn="$machinenumber"
while echo "$mn"|grep -q '^0';do mn=$(echo "$mn"|cut -c2-);done
iptables -t nat -I POSTROUTING -s 10.($machinetype).($mn).0/24 -j MASQUERADE

Works with both bash and dash shells.

In bash it is most simple:

%> a=00123
%> b=${a//0/}

The value of b is now "123". The general form is ${varname//find/replace} and it replaces any number of occurrences of find.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!