Linux-скрипт, считывающий ini-файл и разбивающий на переменные по указанному символу

#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 . Единственным недостатком конвейера вместо одного процесса является то, что вы создаете подоболочку для каждой утилиты и канала. Для больших файлов, которые значительно повышают эффективность.