Удаление ведущих нулей перед передачей переменной оболочки другой команде
Оказывается, что 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
Ответы
Ответ 1
Мне пришлось пересмотреть этот код на днях из-за некоторых несвязанных вещей, и из-за совместимости с каким-либо другим программным обеспечением, которое читает тот же самый script, мне было намного проще переписать его в это, что все равно должно быть действительный bash:
iptables -t nat -I POSTROUTING -s 10.($machinetype).($machinenumber + 0).0/24 -j MASQUERADE
В принципе, добавление 0 заставляет его интерпретироваться как целое число, следовательно, автоматически удаляя ведущие нули
Ответ 2
Вам не нужно использовать 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, результатом будет пустая строка.
Ответ 3
Нет, вы делаете все (allomost all) правильным.
Вы просто должны:
- удалить пробелы вокруг
=
- используйте
$()
или 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
Ответ 4
вы также можете сделать
machinenumber=$(expr $machinenumber + 0)
Ответ 5
Я не могу комментировать, поскольку у меня недостаточно репутации, но я предлагаю вам принять ответ Дениса (это действительно довольно аккуратно)
Во-первых, я не думаю, что ваш ответ действительно 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*//'
>
Ответ 6
nozero=$(echo $machinenumber | sed 's/^0*//')
Попробуйте без пробелов вокруг =
и с дополнительным знаком $
.
Ответ 7
Чистое решение bash:
> N=0001023450
> [[ $N =~ "0*(.*)" ]] && N=${BASH_REMATCH[1]}
> echo $N
1023450
Ответ 8
Использование 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
Ответ 9
Я делаю это, используя
awk '{print $1 + 0}'
Мне нравится это лучше, чем подход sed, поскольку он все еще работает с числами вроде 0, 000 и 001.
Итак, в вашем примере я бы заменил
nozero=$(echo $machinenumber | sed 's/^0*//')
с
nozero=$(echo $machinenumber | awk '{print $1 + 0}' )
Ответ 10
Я также не могу комментировать или голосовать, но ответ 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.
Ответ 11
Я бы сказал, что вы очень близки. Я не вижу требования для 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_]
Используя это решение, вы не теряете нуль в качестве потенциального значения и должны быть переносимыми во всех оболочках.
Ответ 12
В bash это наиболее просто:
%> a=00123
%> b=${a//0/}
Значение b теперь "123".
Общая форма ${varname//find/replace}
и заменяет любое количество вхождений find
.