Bash - 解析 ini 文件,通过其中的值查找节名称

Bash - parsing ini file, finding section name by values within

我有一个 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

脚本会 return 4 (因为所有 3 个参数都匹配 group4)

找到单个值是小菜一碟

source config.ini

并且每个值都在 $valX 下可用,但这不是解析部分名称,因此在这种情况下它是无用的..

能否请您尝试以下,它是 shell 脚本的形式,人们需要通过向脚本提供参数来 运行(使用所示示例测试和编写)。

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=[=10=]
  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=[=12=]                 ##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.

你可以使用这个 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 = [=10=]
   gsub(/^\[group|\]$/, "", grp)
}
NF == 2 && values[] && !seen[]++ {
   found++
}
END {
   if (n == found)
      print grp
}' file

4

Code Demo

您的脚本 script.sh 可能是这样的:

#!/bin/bash

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

如果您使用上面的 更新 config.ini 文件发出 ./script.sh 100 0x20 105,输出将是:

4

条目 base=...hwaddr=...lock=... 必须始终按此顺序出现在 config.ini 中以进行匹配。如果不是这样,请让我改编脚本。

Sed 变体

#!/bin/bash
val1= # get value1
val2= # get value2
val3= # 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.*//p"

用法

$ ./test xyz xyy zyx
4

只要你的输入数据有名称-值对,最好先创建一个数组(下面的f[])将这些名称映射到它们的值,然后在每条记录的末尾你可以简单地比较值按您喜欢的任何组合使用他们的名字,并按您喜欢的任何顺序打印您喜欢的任何值,只需按他们的名字引用它们。

$ cat tst.awk
BEGIN { FS=" *= *"; OFS="=" }
NF {
    if ( /]/ ) {
        gsub(/[^0-9]/,"")
        f["group"] = [=10=]
    }
    else {
        f[] = 
    }
    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