Удаление ведущих нулей перед передачей переменной оболочки другой команде

оказывается, iptables не слишком хорошо справляется с ведущими нулями. As $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

13 ответов


вам не нужно использовать 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, результатом будет null строка.


нет, вы делаете все (почти все) правильно. Вы просто должны:

  • удалить пробелы вокруг =
  • использовать $() или backticks вместо ()

это было бы правильно:

 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

вы также можете сделать

machinenumber=$(expr $machinenumber + 0)

Я не могу комментировать, поскольку у меня нет достаточной репутации, но я бы предложил вам принять Дениса (что действительно довольно аккуратно)

во-первых, я не думаю, что ваш ответ является действительным 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*//'

>

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

попробуйте без пробелов вокруг = и дополнительно $ знак.


чистое решение bash:

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

использование sed:

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

Я делаю это с помощью

awk '{print  + 0}'

мне это нравится больше, чем подход sed, поскольку он все еще работает с числами, такими как 0, 000 и 001.

поэтому в вашем примере я бы заменил

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

С

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


Я также не могу комментировать или голосовать, но ответ Дункана Ирвина лучший.

Я хотел бы добавить примечание о переносимости. The $((10#0009)) синтаксис не портативный. Он работает в bash и ksh, но не в dash:

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

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

Если для вас важна переносимость, используйте ответ sed.


Я бы сказал, что вы очень близки. Я не вижу требования для 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_]

используя это решение, вы не теряете ноль в качестве потенциального значения и должны быть переносимыми во всех оболочках.


мне пришлось пересмотреть этот код на днях из-за некоторых несвязанных вещей, и из-за совместимости с некоторым другим программным обеспечением, которое читает тот же скрипт, я нашел его намного проще переписать в это, что все равно должно быть действительным bash:

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

в принципе, добавление 0 заставляет его интерпретироваться как целое число, поэтому автоматически удаляет ведущие нули


Если вы используете bash, это кажется простым:

nozero=$(bc<<<$machinenumber)

в bash это самое простое:

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

значение b теперь "123". Общая форма ${varname//find/replace} и заменяет любое количество find.