값에 특정 문자가 포함될 수 있는 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]삽입하세요 .awksedwhile

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

( 물론 명령줄 "$inifile"끝에서 제거 sed하십시오. 파일에서만 추출하는 수고를 겪은 후에 파일을 다시 공급하고 싶지는 않을 것입니다 [Section1]).

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

답변2

나는 그것이 불완전한 대답이라는 것을 알고 있지만 MySQL.lnsin augeas는 그 대부분을 구문 분석할 수 있는 것 같습니다. 안에 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

유일하게 엉망인 것은 마지막 것이고 TBH는 오류가 아닌 것 같습니다. 파일 에서 .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/
sudo apt install crudini
Ubuntu에서는 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
$

관련 정보