Bash - анализ INI-файла, поиск имени раздела по значениям в пределах - PullRequest
2 голосов
/ 04 марта 2020

У меня есть файл config.ini, который выглядит следующим образом (обновлено):

[group1]
base=100
hwadd=0x20
doorstatus=100
lock=101
bookingnr=010100
kode=1111
inuse=0

[group2]
base=100
hwadd=0x20
doorstatus=100
lock=102
bookingnr= 010101
kode=1111
inuse=0

[group3]
base=100
hwadd=0x20
doorstatus=100
lock=103
bookingnr=010103
kode=1111
inuse=0

[group4]
base=100
hwadd=0x20
doorstatus=100
lock=105
bookingnr=010105
kode=1111
inuse=0

[group5]
base=100
hwadd=0x20
doorstatus=100
lock=106
bookingnr=010106
kode=1111
inuse=0

[group6]
base=100
hwadd=0x20
doorstatus=100
lock=107
bookingnr=010107
kode=1111
inuse=0

[group7]
base=100
hwadd=0x21
doorstatus=100
lock=101
bookingnr=010108
kode=1111
inuse=0

[group8]
base=100
hwadd=0x21
doorstatus=100
lock=102
bookingnr=010109
kode=1111
inuse=0
...

Мне нужно получить номер комнаты, где 3 заданных значения ( base , hwadd , lock ) соответствуют параметрам скрипта. Допустим, скрипт bash был назван так:

script.sh 100 0x20 105

скрипт вернет 4 (поскольку все 3 параметра соответствуют group4)

Поиск одного значение - это кусок пирога

source config.ini

, и каждое значение доступно в $ valX , но это не синтаксический анализ имен разделов, поэтому в данном случае он бесполезен ..

Ответы [ 5 ]

1 голос
/ 05 марта 2020

Всякий раз, когда ваши входные данные имеют пары имя-значение, лучше сначала создать массив (f[] ниже), который сопоставляет эти имена с их значениями, а затем в конце каждой записи вы можете просто сравнивать значения по их именам в любую комбинацию, которую вы любите, и печатайте любые значения, которые вам нравятся, в любом порядке, просто ссылаясь на них по именам.

$ cat tst.awk
BEGIN { FS=" *= *"; OFS="=" }
NF {
    if ( /]/ ) {
        gsub(/[^0-9]/,"")
        f["group"] = $0
    }
    else {
        f[$1] = $2
    }
    next
}
{ prt() }
END { prt() }

function prt() {
    if ( (f["base"] == base) && (f["hwadd"] == hwadd) && (f["lock"] == lock) ) {
        print f["group"]
    }
    delete f
}

$ awk -v base=100 -v hwadd=0x20 -v lock=105 -f tst.awk file
4
1 голос
/ 04 марта 2020

Вы можете использовать этот awk:

val='100 0x20 105'

awk -F= -v vals="$val" 'BEGIN {
   n = split(vals, w, /[ \t]+/)
   for (i=1; i<=n; i++)
      values[w[i]] = 1
}
/^\[group[0-9]+]$/ {
   if (n == found)
      print grp
   delete seen
   found = 0
   grp = $0
   gsub(/^\[group|\]$/, "", grp)
}
NF == 2 && values[$2] && !seen[$2]++ {
   found++
}
END {
   if (n == found)
      print grp
}' file

4

Код демонстрации

1 голос
/ 04 марта 2020

Ваш сценарий script.sh может быть таким:

#!/bin/bash

sed '/^\[/p;/^base/p;/^hwadd/p;/^lock/p;d' config.ini |   # keep relevant lines
awk '
  BEGIN{RS = "["; FS = "\n"}
  {print $1, $2, $3, $4}
' |                                   # awk puts each block on one line
grep "base=$1 hwadd=$2 lock=$3" |     # filter line matching all records
sed -e 's/^group//' -e 's/\].*$//'    # extract group # from matching line

Если вы выдадите ./script.sh 100 0x20 105 с обновленным config.ini файлом выше, вывод будет:

4

Необходимо, чтобы записи base=..., hwaddr=... и lock=... всегда появлялись в этом порядке в config.ini для совпадения. Если это не так, пожалуйста, попросите меня адаптировать скрипт.

1 голос
/ 04 марта 2020

Не могли бы вы попробовать следующее, это в форме сценария оболочки, который нужно запустить, предоставив аргументы сценарию (протестировано и написано с показанными образцами).

cat script.ksh
val="$@"

awk -v arg="$val" '
BEGIN{
  FS="="
  num=split(arg,array," ")
  for(i=1;i<=num;i++){
    array1[array[i]]
  }
}
/group/{
  if(sum==num){
    print group_value
  }
  sum=""
  gsub(/[^0-9]*/,"")
  group_value=$0
  next
}
($NF in array1){
  sum++
}
END{
  if(sum==num){
    print group_value
  }
}
'  Input_file

Когда я запускаю его следующим образом:

./script.ksh xyz xyy zyx
3


Объяснение: Добавление подробного объяснения приведенного выше кода здесь.

cat script.ksh
val="$@"                         ##Creating a shell variable named val which has all values of arguments passed to script.
awk -v arg="$val" '              ##Starting an awk program from here and creating a variable arg whose value is shell variable val here.
BEGIN{                           ##Starting BEGIN section from here.
  FS="="                         ##Setting FS as = here.
  num=split(arg,array," ")       ##Splitting arg variable into an array with delimiter as space here.
  for(i=1;i<=num;i++){           ##Running for loop from i=1 to till value of num here.
    array1[array[i]]             ##Creating an array named array1 with index of value of array with index i here.
  }
}
/group/{                         ##Checking condition if line contains group string then do following.
  if(sum==num){                  ##Checking condition if sum==num then do following.
    print group_value            ##Printing variable group_value here.
  }
  sum=""                         ##Nullifying variable sum here.
  gsub(/[^0-9]*/,"")             ##Globally substituting everything apart from digits with NULL here in current line.
  group_value=$0                 ##Setting variable group_value value to current line value here.
  next                           ##next will skip all further statements from here.
}
($NF in array1){                 ##Checking condition if last field of current line is present in array1 then do following.
  sum++                          ##Increase count of sum variable with 1 here.
}
END{                             ##Starting END block for this code here.
  if(sum==num){                  ##Checking condition if sum==num then do following.
    print group_value            ##Printing variable group_value here.
  }
}
'  Input_file                    ##Mentioning Input_file name here.
0 голосов
/ 04 марта 2020

Sed вариант

#!/bin/bash
val1=$1 # get value1
val2=$2 # get value2
val3=$3 # get value3
file="config.ini"   # ini file
raw=$(cat "$file")  # read file to this var
raw=${raw//$'\n'/ } # change new line to space
raw=${raw//[/'\n'}  # change [ to new line
# print through sed, sed prints number of group in matched string
printf "$raw" | sed -n "s/group\([0-9]*\).*$val1.*$val2.*$val3.*/\1/p"

Использование

$ ./test xyz xyy zyx
4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...