Мы можем использовать синтаксис ${var##pattern}
и ${var%%pattern}
извлечь последний и первый раздел адреса IPv4:
IP=109.96.77.15
echo IP: $IP
echo 'Extract the first section using ${var%%pattern}: ' ${IP%%.*}
echo 'Extract the last section using ${var##pattern}: ' ${IP##*.}
Как мы можем извлечь второй или третий раздел адреса IPv4, используя расширение параметра?
Вот мое решение: я использую массив и изменяю переменную IFS.
:~/bin$ IP=109.96.77.15
:~/bin$ IFS=. read -a ArrIP<<<"$IP"
:~/bin$ echo ${ArrIP[1]}
96
:~/bin$ printf "%s\n" "${ArrIP[@]}"
109
96
77
15
Кроме того, я написал несколько решений с использованием awk
, sed
и cut
команды.
Теперь мой вопрос: существует ли более простое решение, основанное на расширении параметров, которое не использует изменение массива и IFS?
IFS
дляread
там:IFS=. read -a ArrIP<<<"$IP"
IFS=. read a b c d <<< "$IP"
, не приемлемая (если вы используете Bash, то есть)? Почему это должно быть сделано с расширением параметра?Ответы:
Предполагая значение IFS по умолчанию, вы извлекаете каждый октет в его собственную переменную с помощью:
Или в массив с:
источник
Ваша постановка проблемы может быть немного более либеральной, чем вы предполагали. На риск использования лазейки, вот решение, на которое ссылается Муру :
Это несколько неуклюже. Он определяет две одноразовые переменные и не может быть легко адаптирован для обработки большего количества разделов (например, для адреса MAC или IPv6). Ответ Сергея Колодяжного вдохновил меня обобщить сказанное на это:
Это наборы
sec1
,sec2
,sec3
иsec4
, которые могут быть провереныwhile
Цикл должен быть легко понять - он перебирает четыре раза.slice
качестве имени переменной , которая занимает местоlast3
иlast2
в моем первом растворе (выше).declare sec"$count"="value"
это способ назначитьsec1
,sec2
,sec3
и ,sec4
когдаcount
это1
,2
,3
и4
. Это немного похожеeval
, но безопаснее.value
,"${slice%%.*}"
аналогичен значениям, которые присваивает мой исходный ответfirst
,second
иthird
.источник
Я действительно понимаю, что вы специально просили решение, которое НЕ было временно переопределено
IFS
, но у меня есть приятное и простое решение, которое вы не рассмотрели, поэтому вот так:Это короткая команда поставит элементы вашего IP - адреса в оболочечных позиционных параметров
$1
,$2
,$3
,$4
. Тем не менее, вы, вероятно, захотите сначала сохранить оригинал,IFS
а затем восстановить его.Кто знает? Может быть, вы пересмотрите и примете этот ответ за его краткость и эффективность.
(Это было ранее неправильно указано как
IFS=. set -- $IP
)источник
IFS
в той же командной строке, новое значение не вступает в силу, когда переменные в той же командной строке раскрываются. То же, что и сx=1; x=2 echo $x
set
вообще не использует$IFS
,$IFS
используется только для разделения слов$IP
, но здесь он назначается слишком поздно, так что это не имеет никакого эффекта. Этот ответ в основном неверен.IP=109.96.77.15 bash -c 'IFS=. set -- $IP; echo "$2"'
ничего не выводит ли в режиме POSIX или нет. Вам нужноIFS=. command eval 'set -- $IP'
, илиIFS=. read a b c d << "$IP"
.
в одном из ваших предыдущих тестов. Беги,IP=1.2.3.4 bash -xc 'IFS=. set $IP; echo "$2"'
и ты увидишь, что это не работает. И посмотрите,IP=1.2.3.4 bash -o posix -xc 'IFS=. set $IP; echo "\$1=$1 \$2=$2 IFS=$IFS"'
чтобы проиллюстрировать точку зрения @ chepner.Не самый простой , но вы можете сделать что-то вроде:
Это должно работать в ksh93 (где , что
${var//pattern/replacement}
оператор приходит от),bash
4.3+, BusyBoxsh
,yash
,mksh
иzsh
, хотя, конечно , вzsh
, есть гораздо более простые подходы . В старых версияхbash
вам нужно будет удалить внутренние кавычки. Это работает с теми внутренними кавычками, удаленными в большинстве других оболочек, но не ksh93.Это предполагает, что
$IP
содержит правильное четырехзначное представление адреса IPv4 (хотя это также будет работать для четырехугольных представлений типа0x6d.0x60.0x4d.0xf
(и даже восьмеричных в некоторых оболочках), но вывести значения в десятичном виде). Если содержимое$IP
приходит из ненадежного источника, это равносильно уязвимости, связанной с внедрением команд.В принципе, так как мы заменяем каждый
.
в$IP
с+256*(
, мы в конечном итоге оценка:Таким образом , мы построения 32 разрядное целое число из этих 4 байта , как IPv4 - адрес в конечном счете , является (хотя и с байты в обратном порядке ) ¹ , а затем , используя
>>
,&
битовые операторы для извлечения соответствующих байтов.Мы используем
${param+value}
стандартный оператор (здесь,$-
который гарантированно будет всегда установлен), а не простоvalue
потому, что в противном случае арифметический синтаксический анализатор будет жаловаться на несовпадающие скобки. Оболочка здесь может найти закрытие))
для открытия$((
, а затем выполнить расширения внутри, что приведет к вычислению арифметического выражения.С
вместо этого, оболочка будет рассматривать второй и третий$(((${IP//./"+256*("}))))&255))
)
МЕЕТСЯ как закрытие))
для$((
и сообщит об ошибке.В ksh93 вы также можете сделать:
bash
,mksh
,zsh
Скопировали ksh93 игровую${var/pattern/replacement}
оператора , но не то, что обработка части захвата-группы.zsh
поддерживает его с другим синтаксисом:bash
поддерживает некоторую форму обработки группы захвата в своем операторе сопоставления регулярных выражений , но не в${var/pattern/replacement}
.POSIXly, вы бы использовали:
noglob
, Чтобы избежать неприятных сюрпризов для значений ,$IP
как10.*.*.*
, подоболочка ограничить сферу действия этих изменений параметров и$IFS
.Address IPv4-адрес - это всего лишь 32-разрядное целое число, а, например, 127.0.0.1 - это лишь одно из многих (хотя и наиболее распространенных) текстовых представлений. Тот же типичный IPv4-адрес интерфейса обратной связи также может быть представлен как 0x7f000001 или 127.1 (возможно, здесь более уместно сказать, что это
1
адрес в сети класса 127.0 / 8), или 0177.0.1, или другими комбинациями 1 до 4 чисел, выраженных как восьмеричное, десятичное или шестнадцатеричное. Вы можете передать все это,ping
например, и увидите, что все они будут пинговать localhost.Если вы не возражаете против побочного эффекта установки произвольной временной переменной (здесь
$n
), вbash
илиksh93
илиzsh -o octalzeroes
илиlksh -o posix
, вы можете просто преобразовать все эти представления обратно в 32-битное целое число с помощью:А затем извлеките все компоненты с помощью
>>
/&
комбинаций, как указано выше.mksh
использует 32-разрядные целые числа со знаком для своих арифметических выражений, вы можете использовать$((# n=32,...))
их для принудительного использования 32-разрядных чисел без знака (иposix
возможность распознавать восьмеричные константы).источник
${-+
раньше. Я также не могу найти никакой документации по этому вопросу. Это работает, но мне просто любопытно подтвердить, это просто превратить строку в математическое выражение? Где я могу найти формальное определение? Кроме того, дополнительные цитаты в разделе замены расширения параметров не работают в GNU bash, версия 4.1.2 (2) -релиз CentOS 6.6. Я должен был сделать это вместо этогоecho "$((${-+"(${IP//./+256*(}))))"}>>16&255))"
С zsh вы можете вкладывать подстановки параметров:
Это невозможно в bash.
источник
zsh
, вы можете предпочесть${${(s(.))ip}[3]}
Конечно, давайте играть в игру со слоном.
или
источник
С
IP=12.34.56.78
.А также
Описание:
Использование раскрытия параметра
${IP// }
для преобразования каждой точки в ip в открывающую скобку, точку и закрывающую скобку. Добавляя начальные скобки и закрывающие скобки, мы получаем:который создаст четыре круглых скобки для соответствия регулярному выражению в синтаксисе теста:
Это позволяет печатать массив BASH_REMATCH без первого компонента (все совпадения с регулярным выражением):
Количество круглых скобок автоматически подбирается к соответствующей строке. Таким образом, это будет соответствовать MAC-адресу или EUI-64 IPv6-адреса, несмотря на то, что они имеют разную длину:
Используй это:
источник
Вот небольшое решение, сделанное с POSIX
/bin/sh
(в моем случае этоdash
), функцией, которая многократно использует расширение параметров (поэтомуIFS
здесь нет ) и именованные каналы, и включаетnoglob
опцию по причинам, упомянутым в ответе Стефана .Это работает так:
И с
ip
изменено на109.*.*.*
Счетчик циклов, состоящий из 4 итераций, учитывает 4 секции действительного адреса IPv4, в то время как акробатика с именованными каналами учитывает необходимость дальнейшего использования секций IP-адреса в скрипте, в отличие от того, что переменные застряли в подоболочке цикла.
источник
Почему бы не использовать простое решение с awk?
$ IP="192.168.1.1" $ echo $IP | awk -F '.' '{ print $1" "$2" "$3" "$4;}'
Результат
$ 192 168 1 1
источник
источник