값에 특정 문자가 포함될 수 있는 ini 파일을 구문 분석하는 방법은 무엇입니까?

값에 특정 문자가 포함될 수 있는 ini 파일을 구문 분석하는 방법은 무엇입니까?

나는 여러 bash ini 구문 분석 스크립트를 살펴보았고 다음과 같은 내용을 보았습니다.이것여기서 몇 번 사용해 본 적이 있어서 그것이 나에게 효과가 있는지 알아보고 싶었습니다. ini 파일을 한 줄씩 여러 번 읽는 것처럼 보이며 각 패스는 최종적으로 평가되는 함수를 점진적으로 구성합니다. 일부 특수 문자에서는 작동하지만 다른 문자에서는 작동하지 않습니다. 파일의 값에 작은따옴표나 기호보다 크거나 작은 기호가 포함되어 있으면 스크립트는 구문 오류를 반환합니다. 다른 기호도 예상치 못한 결과를 초래할 수 있습니다. 이런 캐릭터를 만나면 어떻게 해야 하나요?

ini를 파싱하는 함수입니다.

#!/usr/bin/env bash
cfg_parser ()
{
    ini="$(<$1)"                # read the file
    ini="${ini//[/\[}"          # escape [
    ini="${ini//]/\]}"          # escape ]
    IFS=$'\n' && ini=( ${ini} ) # convert to line-array
    ini=( ${ini[*]//;*/} )      # remove comments with ;
    ini=( ${ini[*]/\    =/=} )  # remove tabs before =
    ini=( ${ini[*]/=\   /=} )   # remove tabs be =
    ini=( ${ini[*]/\ =\ /=} )   # remove anything with a space around =
    ini=( ${ini[*]/#\\[/\}$'\n'cfg.section.} ) # set section prefix
    ini=( ${ini[*]/%\\]/ \(} )    # convert text2function (1)
    ini=( ${ini[*]/=/=\( } )    # convert item to array
    ini=( ${ini[*]/%/ \)} )     # close array parenthesis
    ini=( ${ini[*]/%\\ \)/ \\} ) # the multiline trick
    ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2)
    ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis
    ini[0]="" # remove first element
    ini[${#ini[*]} + 1]='}'    # add the last brace
    eval "$(echo "${ini[*]}")" # eval the result
}

ini 파일

[Section1]
value1=abc`def # unexpected EOF while looking for matching ``'
value2=ghi>jkl # syntax error near unexpected token `>'
value3=mno$pqr # executes ok but outputs "mnoqr"
value4=stu;vwx # executes ok but outputs "stu"

답변1

사실은 너야할 수 있는뭔가를 한다는 것이 bash당신을 의미하는 것은 아니다~해야 한다.

sh( bash등) 스크립트는 프로그램을 시작하거나 텍스트 처리 명령을 처리하기 위한 상대적으로 간단한 래퍼로 가장 잘 작동합니다. ini 파일 구문 분석 및 조작을 포함하여 더 복잡한 작업의 경우 다른 언어가 더 적합합니다. perl또는 에서 스크립트 작성을 고려해 보셨나요 python? 둘 다 좋은 .ini 파일 파서를 가지고 있습니다. Config::INI저는 ini 파일을 파싱해야 할 때 Perl의 모듈을 여러 번 사용했습니다.

그러나 bash에서 이 작업을 고집한다면 단일 변수를 설정하는 대신 연관 배열을 사용해야 합니다.

다음과 같이 시작하십시오.

#! /bin/bash

inifile='user1074170.ini' 

# declare $config to be an associative array
declare -A config

while IFS='=' read -r key val ; do 
    config["$key"]="$val"
done <  <(sed -E -e '/^\[/d
                     s/#.*//
                     s/[[:blank:]]+$|^[[:blank:]]+//g' "$inifile" )

# now print out the config array
set | grep '^config='

스크립트 sed는 해당 [Section1]줄(실제로 여는 대괄호로 시작하는 모든 줄 [- 여러 섹션이 있는 ini 파일에서 이를 다르게 처리해야 함 [1] )을 제거하고 주석과 앞뒤 공백을 제거합니다. 루프 while는 각 줄을 읽고 이를 =필드 구분 기호로 사용하고 내용을 $key 및 $val 변수에 할당하고 $config 배열에 추가합니다.

산출:

config=([value1]="abc\`def" [value3]="mno\$pqr" [value2]="ghi>jkl" [value4]="stu;vwx" )

나중에 스크립트에서 다음과 같이 배열 항목을 사용할 수 있습니다.

$ echo value1 is "${config[value1]}"
value1 is abc`def

$ [ "${config[value4]}" = 'stu;vwx' ] && echo true
true

[1] awk아니면 perl"단락" 모드에서 파일을 편리하게 읽을 수 있는 쉬운 방법이 있습니까? 단락은 하나 이상의 빈 줄로 다른 텍스트 블록과 구분된 텍스트 블록으로 정의됩니다.

예를 들어 만 사용하려면 [Section1]위의 루프에 공급하기 awk전에 아래 스크립트를 삽입하세요 .sedwhile

awk -v RS= -v ORS='\n\n' '/\[Section1\]/' "$inifile" | sed ...

"$inifile"(물론 명령줄 끝에서 파일을 제거하십시오. sed파일을 추출하기 위해 모든 수고를 다한 후에는 파일을 다시 입력하고 싶지 않을 것입니다 [Section1].)

이 설정은 ini 파일에서 섹션 하나만 추출하는 경우 ORS꼭 필요한 것은 아니지만 두 개 이상의 섹션을 추출하는 경우 단락을 분리된 상태로 유지하는 데 유용합니다.

답변2

나는 이것이 불완전한 답변이라는 것을 알고 있지만 MySQL.lnsaugeas에서는 대부분의 답변을 구문 분석할 수 있는 것 같습니다. 존재하다 augtool:

augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> set /augeas/load/testini/lens "MySQL.lns"
augtool> load
augtool> ls /files/root/
.ssh/      test.ini/
augtool> ls /files/root/test.ini
target/ = Section1
augtool> ls /files/root/test.ini/target/
value1/ = abc`def
value2/ = ghi>jkl
value3/ = mno$pqr
value4/ = stu

유일하게 엉망인 것은 마지막 것인데, 솔직히 버그라고는 생각하지 않습니다. .ini파일 에서 세미콜론은 주석의 시작을 표시합니다. 또한 귀하의 데이터가 실제로 이와 같은지 묻고 싶습니다.

그렇다면 sed그 전에 몇 가지 설정을 수행하고 ;사용되지 않은 문자 값을 설정한 다음 다시 후처리로 변환할 수 있습니다. 그러나 궁극적으로 파일이 식별 가능한 구조를 가질 수 있도록 몇 가지 표준이 필요합니다.

편집하다:

PHP 렌즈로 테스트했는데 다음 값을 인용하여 전체 결과를 얻을 수 있습니다.

[root@vlzoreman ~]# augtool
augtool> set /augeas/load/testini/lens "PHP.lns"
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> load
augtool>  ls /files/root/test.ini/Section1/
value1 = abc`def
value2 = ghi>jkl
value3 = mno$pqr
value4 = stu;vwx

그렇지 않으면 MySQL 렌즈만큼 멀리 떨어져 있습니다.

편집 #2:

이것을 작성하는 더 깔끔한 방법이 있다고 확신하지만 다음은 사용 예입니다.

[root@vlp-foreman ~]# bash bash.sh
Values for: Section1:
        :: value1 is abc`def
        :: value2 is ghi>jkl
        :: value3 is mno$pqr
        :: value4 is stu;vwx
Values for: Section2:
        :: value1 is abc`def

스크립트는 다음과 같습니다

#!/bin/bash

sections=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini | cut -f1 -d/)

for currentSection in $sections; do

  echo "Values for: $currentSection:"

  fields=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini/$currentSection | awk '{print $1}')

  for currentField in $fields; do

    currentValue=$(augtool -A --transform "PHP.lns incl /root/test.ini" print /files/root/test.ini/$currentSection/$currentField | cut -f2 -d=)
    currentValue=$(echo $currentValue | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' | sed -e 's/^"//' -e 's/"$//')

    echo -e "\t:: $currentField is $currentValue"

  done

done

답변3

살펴보세요 crudini:https://www.pixelbeat.org/programs/crudini/
Ubuntu에서는 이를 설치하여 sudo apt install crudini
ini 파일에서 값을 읽을 수 있습니다.

$ value1=$(crudini --get "crudini.ini" "Section1" "value1")

crudini는 여러 ini 파일 형식을 지원하고 특수 문자를 처리합니다.

crudini.ini

[Section1]
value1=abc`def
value2=ghi>jkl
value3=mno$pqr
value4=stu;vwx

판독 값

$ for i in {1..4}; do crudini --get "crudini.ini" "Section1" "value$i"; done
abc`def
ghi>jkl
mno$pqr
stu;vwx
$

관련 정보