在将shell变量传递给另一个命令之前删除前导零

时间:2012-06-20 16:13:07

标签: bash strip

事实证明,iptables不能很好地处理前导零。由于使用的$machinenumber必须在其中具有前导零以用于其他目的,因此想法只是基于$nozero创建一个新变量($machinenumber),其中前导零被剥离程。

$machinenumber是01到24之间的两位数字。目前它是09

$machinetype现在是74,并且之前没有造成任何问题。

到目前为止我所拥有的是:

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

虽然我相信自己走在了正确的轨道上,但代码的结果是:

ERROR - Unknown string operation

15 个答案:

答案 0 :(得分:50)

您无需使用sed或其他外部实用程序。以下两种方式Bash可以为您删除前导零。

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

$(())设置算术上下文,10#将数字从基数10转换为基数10,导致任何前导零被删除。

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

启用extglob后,显示的参数展开会删除所有前导零。不幸的是,如果原始值为0,则结果为空字符串。

答案 1 :(得分:21)

不,你让所有(alomost all)正确。 你必须:

  • 删除=
  • 周围的空格
  • 使用$()或反引号代替()

这是正确的:

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

此外,您必须使用不带()的变量。如果您愿意,可以添加""

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

当然,这里的变量不是必需的。你可以简单地说:

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

答案 2 :(得分:16)

你也可以

machinenumber=$(expr $machinenumber + 0)

答案 3 :(得分:8)

我无法评论,因为我没有足够的声誉,但我建议你接受Dennis's answer(这真的很整洁)

首先,我不认为你的答案是有效的bash。 在我的安装中,我得到:

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

如果我引用它,我会得到:

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

我假设你的意思是:

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

但是,当然,由于八进制,它仍然是一个糟糕的解决方案:

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

我认为你的号码目前不是08或09。

这是丹尼斯的:

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

不可否认,最后一个可能是某人的输入验证问题。

sed解决方案存在以下问题:

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

>

答案 4 :(得分:6)

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

尝试不使用=周围的空格并使用额外的$符号。

答案 5 :(得分:5)

纯粹的bash解决方案:

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

答案 6 :(得分:4)

使用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

答案 7 :(得分:3)

我是通过使用

来做到的
awk '{print $1 + 0}'

我比sed方法更喜欢这个,因为它仍适用于0,000和001等数字。

所以在你的例子中我会替换

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

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

答案 8 :(得分:2)

我也无法评论或投票,但Duncan Irvine的答案是最好的。

我想添加一个关于可移植性的说明。 $((10#0009))语法不可移植。它适用于bash和ksh,但不适用于破折号:

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

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

如果可移植性对您很重要,请使用sed答案。

答案 9 :(得分:1)

我会说你很亲密。我没有看到针对bash的要求,但你的非零逻辑是有缺陷的。

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

添加0是将字符串编号更改为非填充整数的常用方法。 bc是一个基本的计算器。我使用这种方法一直从数字中删除空格和零填充。

虽然我不是iptables语法方面的专家,但我很确定括号不是必需的。因为我已经有两个变量边界的非单词字符,所以我不需要在它们周围使用特殊的外壳。单词字符是;

[a-zA-z0-9_]

使用此解决方案,您不会将零作为潜在值丢失,并且应该可以在所有shell中移植。

答案 10 :(得分:1)

如果您正在使用bash,这看起来是最简单的:

nozero=$(bc<<<$machinenumber)

答案 11 :(得分:0)

由于一些不相关的东西,前几天我不得不重新访问这段代码,并且由于与其他一些读同一个脚本的软件的兼容性,我发现把它重写成这个很容易,这应该仍然是有效的bash :

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

基本上,添加0会强制它被解释为整数,因此会自动剥离前导零

答案 12 :(得分:0)

将数字加0,将删除前导零

eg: expr 00010 + 0 #becomes 10

OR

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

答案 13 :(得分:0)

如果您没有sed,awk或perl,则可以使用 cut 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

可与bash和dash外壳一起使用。

答案 14 :(得分:-4)

在bash中最简单:

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

b的值现在是“123”。 一般表格为${varname//find/replace},它会替换find的任意数量的出现次数。