#linux
#linux
Вопрос:
Я застрял в следующей задаче: давайте представим, что у нас есть .ini
файл в папке. Файл содержит строки, подобные этой:
eno1=10.0.0.254/24
eno2=172.16.4.129/25
eno3=192.168.2.1/25
tun0=10.10.10.1/32
Мне пришлось выбрать самую большую маску подсети. Так что моя попытка была:
declare -A data
for f in datadir/name
do
while read line
do
r=(${line//=/ })
let data[${r[0]}]=${r[1]}
done < $f
done
Вот как далеко я продвинулся. (Да, я знаю, что файл с именем name — это не .ini
файл, а a .txt
, поскольку у меня возникли проблемы даже с созданием ini-файла, этот учитель даже не предоставил такой файл для нашего экзамена.)
Он разбивает строку до = , но не хочет считывать IP-номер из-за (первого) . характер.
(Недопустимый арифметический оператор, сообщение об ошибке, которое я получил)
Если бы кто-нибудь мог мне помочь и объяснить, как я могу создать сценарий для подобных задач, я был бы очень благодарен!
Комментарии:
1. Как вы сравниваете IP-адреса? Что делает одно больше другого?
2. Маска подсети — это часть после косой черты. Самой большой маской подсети будет IP-адрес с наибольшим значением после косой черты.
Ответ №1:
Оба ранее представленных решения работают (и делают то, для чего они предназначены); Я подумал, что добавлю что-нибудь в левом поле, поскольку спецификации довольно свободные.
$ cat freasy
eno1=10.0.0.254/24
eno2=172.16.4.129/25
eno3=192.168.2.1/25
tun0=10.10.10.1/32
Я бы сказал, что самая большая маска подсети — это маска с наименьшим числовым значением (содержит наибольшее количество хостов).
$ sort -t/ -k2,2nr freasy| tail -n1
eno1=10.0.0.254/24
Ответ №2:
Не используйте let
. Это для арифметики.
$ help let
let: let arg [arg ...]
Evaluate arithmetic expressions.
Evaluate each ARG as an arithmetic expression.
Просто используйте прямое присваивание:
declare -A data
for f in datadir/name
do
while read line
do
r=(${line//=/ })
data[${r[0]}]=${r[1]}
done < $f
done
Результат:
$ declare -p data
declare -A data=([tun0]="10.10.10.1/32" [eno1]="10.0.0.254/24" [eno2]="172.16.4.129/25" [eno3]="192.168.2.1/25" )
Ответ №3:
awk
предоставляет простое решение для нахождения максимального значения, следующего за '/'
, которое будет на порядки быстрее, чем сценарий bash или конвейер Unix с использованием:
awk -F"=|/" '$3 > max { max = $3 } END { print max }' file
Пример использования/ Вывода
$ awk -F"=|/" '$3 > max { max = $3 } END { print max }' file
32
Выше awk
разделяются поля с использованием либо '='
или '/'
в качестве разделителя полей, а затем сохраняется максимальное значение 3-го поля $3
и выводится это значение с помощью END {...}
правила.
Решение Bash
Если вам действительно нужно решение с использованием скрипта bash, то вы можете изолировать нужные части каждой строки, используя [[ .. =~ .. ]]
для заполнения BASH_REMATCH
массива, а затем сравнить ${BASH_REMATCH[3]}
с max
переменной. [[ .. ]]
Выражение with =~
рассматривает все, что находится в правой части, как расширенное регулярное выражение и изолирует каждую группировку ( (...)
) как элемент в массиве BASH_REMATCH
, например
#!/bin/bash
[ -z "$1" ] amp;amp; { printf "filename requiredn" >amp;2; exit 1; }
declare -i max=0
while read -r line; do
[[ $line =~ ^(.*)=(.*)/(.*)$ ]]
((${BASH_REMATCH[3]} > max)) amp;amp; max=${BASH_REMATCH[3]}
done < "$1"
printf "max: %sn" "$max"
Использование только расширений параметров POSIX
Используя расширение параметров с удалением подстроки, поддерживаемое оболочкой POSIX (оболочка Bourne, dash и т. Д.), Вы могли бы сделать:
#!/bin/sh
[ -z "$1" ] amp;amp; { printf "filename requiredn" >amp;2; exit 1; }
max=0
while read line; do
[ "${line##*/}" -gt "$max" ] amp;amp; max="${line##*/}"
done < "$1"
printf "max: %sn" "$max"
Пример использования / вывода
После создания yourscript.sh
исполняемого файла с chmod x yourscript.sh
помощью , вы бы сделали:
$ ./yourscript.sh file
max: 32
(одинаковый вывод для обоих решений сценария оболочки)
Дайте мне знать, если у вас возникнут дополнительные вопросы.
Комментарии:
1. Похоже, это
bash
программная задача, поэтому утилиты могут быть исключены. Если нет, можно использоватьsort -t'/' -k2 -r -n datadir/name | head -1|cut -d'/' -f2
`2. Он был помечен
[linux]
так, что, как правило, охватывает утилиты Linux, такие какsort
илиawk
. Единственным недостатком конвейера вместо одного процесса является то, что вы создаете подоболочку для каждой утилиты и канала. Для больших файлов, которые значительно повышают эффективность.