Удаление ведущих нулей перед передачей переменной оболочки другой команде
оказывается, 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
Я не могу комментировать, поскольку у меня нет достаточной репутации, но я бы предложил вам принять Дениса (что действительно довольно аккуратно)
во-первых, я не думаю, что ваш ответ является действительным 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 это самое простое:
%> a=00123
%> b=${a//0/}
значение b теперь "123".
Общая форма ${varname//find/replace}
и заменяет любое количество find
.