在bash中解析.ini文件

时间:2018-03-21 06:53:20

标签: bash ini

我有一个下面的属性文件,并希望解析它,如下所述。请帮忙。

我创建的

.ini文件:

[Machine1]

app=version1


[Machine2]

app=version1

app=version2

[Machine3]

app=version1
app=version3

我正在寻找一种解决方案,其中应该像

一样解析ini文件
[Machine1]app = version1
[Machine2]app = version1
[Machine2]app = version2
[Machine3]app = version1
[Machine3]app = version3

感谢。

4 个答案:

答案 0 :(得分:4)

尝试:

$ awk '/\[/{prefix=$0; next} $1{print prefix $0}' file.ini
[Machine1]app=version1
[Machine2]app=version1
[Machine2]app=version2
[Machine3]app=version1
[Machine3]app=version3

工作原理

  • /\[/{prefix=$0; next}

    如果任何行以[开头,我们将该行保存在变量prefix中,然后我们跳过其余命令并跳转到next行。

  • $1{print prefix $0}

    如果当前行不为空,我们打印前缀后跟当前行。

添加空格

=

的任何位置周围添加空格
$ awk -F= '/\[/{prefix=$0; next} $1{$1=$1; print prefix $0}' OFS=' = ' file.ini
[Machine1]app = version1
[Machine2]app = version1
[Machine2]app = version2
[Machine3]app = version1
[Machine3]app = version3

这可以使用=作为输入的字段分隔符,=作为输出的字段分隔符。

答案 1 :(得分:2)

您可以尝试使用awk

 awk '/\[[^]]*\]/{          # Match pattern like [...]
        a=$1;next           # store the pattern in a
      } 
      NF{                   # Match non empty line
        gsub("=", " = ")    # Add space around the = character
        print a $0          # print the line
     }' file

答案 2 :(得分:1)

这里有很好的答案。我对@davfive 的函数进行了一些修改,以使其更适合我的用例。除了允许 = 字符前后有空格,并允许值中包含空格外,此版本基本相同。

# Get values from a .ini file
function iniget() {
    if [[ $# -lt 2 || ! -f $1 ]]; then
        echo "usage: iniget <file> [--list|<section> [key]]"
        return 1
    fi
    local inifile=$1
    
    if [ "$2" == "--list" ]; then
        for section in $(cat $inifile | grep "^\\s*\[" | sed -e "s#\[##g" | sed -e "s#\]##g"); do
            echo $section
        done
        return 0
    fi
    
    local section=$2
    local key
    [ $# -eq 3 ] && key=$3
    
    # This awk line turns ini sections => [section-name]key=value
    local lines=$(awk '/\[/{prefix=$0; next} $1{print prefix $0}' $inifile)
    lines=$(echo "$lines" | sed -e 's/[[:blank:]]*=[[:blank:]]*/=/g')
    while read -r line ; do
        if [[ "$line" = \[$section\]* ]]; then
            local keyval=$(echo "$line" | sed -e "s/^\[$section\]//")
            if [[ -z "$key" ]]; then
                echo $keyval
            else          
                if [[ "$keyval" = $key=* ]]; then
                    echo $(echo $keyval | sed -e "s/^$key=//")
                fi
            fi
        fi
    done <<<"$lines"
}

答案 3 :(得分:0)

我喜欢@ John1024的答案。我一直在寻找那个。我创建了一个bash函数,该函数可让我根据他的想法查找部分或特定键:

function iniget() {
  if [[ $# -lt 2 || ! -f $1 ]]; then
    echo "usage: iniget <file> [--list|<section> [key]]"
    return 1
  fi
  local inifile=$1

  if [ "$2" == "--list" ]; then
    for section in $(cat $inifile | grep "\[" | sed -e "s#\[##g" | sed -e "s#\]##g"); do
      echo $section
    done
    return 0
  fi

  local section=$2
  local key
  [ $# -eq 3 ] && key=$3

  # https://stackoverflow.com/questions/49399984/parsing-ini-file-in-bash
  # This awk line turns ini sections => [section-name]key=value
  local lines=$(awk '/\[/{prefix=$0; next} $1{print prefix $0}' $inifile)
  for line in $lines; do
    if [[ "$line" = \[$section\]* ]]; then
      local keyval=$(echo $line | sed -e "s/^\[$section\]//")
      if [[ -z "$key" ]]; then
        echo $keyval
      else          
        if [[ "$keyval" = $key=* ]]; then
          echo $(echo $keyval | sed -e "s/^$key=//")
        fi
      fi
    fi
  done
}

因此将其命名为file.ini

[Machine1]
app=version1
[Machine2]
app=version1
app=version2
[Machine3]
app=version1
app=version3

然后产生以下结果

$ iniget file.ini --list
Machine1
Machine2
Machine3

$ iniget file.ini Machine3
app=version1
app=version3

$ iniget file.ini Machine1 app
version1

$ iniget file.ini Machine2 app
version2
version3

再次,感谢@ John1024的回答,我努力尝试创建一个支持部分的简单bash ini解析器。

  

在Mac上使用GNU bash 5.0.0(1)-发行版(x86_64-apple-darwin18.2.0)进行了测试