Подтвердить что ты не робот

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

Оказывается, что 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
4b9b3361

Ответ 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.