regex - sed regular expression+



sed:.yml 파일의 환경 속성 값 변경 (4)

응용 프로그램의 환경 속성을 구성하는 .yml 파일이 있습니다 (예 :

env1:
  :prop1: "value1"
  :prop2: "value2"
        ...
  :propn: "valuen"

env2:
  :prop1: "value1"
  :prop2: "value2"
  :prop3: "value3"
        ...
  :propn: "valuen"

    ...

envn:
  :prop1: "value1"
  :prop2: "value2"
        ...
  :propn: "valuen"

다음 인터페이스로 bash 스크립트를 작성하고 싶습니다.

$ change_env.sh <environment> <property> <new value> <file.yml>

예:

$ change_env.sh env2 prop3 "this value was changed" file.yml

출력은 다음과 같습니다.

env1:
  :prop1: "value1"
  :prop2: "value2"
        ...
  :propn: "valuen"

env2:
  :prop1: "value1"
  :prop2: "value2"
  :prop3: "this value was changed"
        ...
  :propn: "valuen"

    ...

envn:
  :prop1: "value1"
  :prop2: "value2"
        ...
  :propn: "valuen"

나는이 게시물을 찾았지만, 내 사건을 해결할 수는 없었다. XML 요소의 값을 바꿉니 까? 정규 표현식?

나도 이것을 시도 : (모든 속성을 변경하기 때문에 실패합니다)

sed 's/\(:pro3:\).*/\1 "new value"/'

미리 감사드립니다. - Lourenco.

https://code.i-harness.com


(아주 좋은 첫 번째 게시물!)

이 시도

cat change_env.sh

#!/bin/bash
# spec : change_env.sh <environment> <property> <new value> <file.yml>

case ${#} in [!4] ) 
    echo "usage: change_env.sh <environment> <property> <new value> <file.yml>" 1>&2
    exit 1 
   ;; 
esac

env="$1" prop="$2" new="$3" file="$4"
bakFile="${file}".bak
mv "$file" "$bakFile"
sed '/^'"${env}"'/,/^[   ]*$/{  # [ spaceChar tabChar ]
        /'"${prop}"'/s/\('"${prop}"'\)\(.*$\)/\1'"${new}"'/
    }' "$bakFile" > "$file"

편집하다

입력 내용에 값에 공백이 포함될 것으로 예상되면 스크립트를 수정하여 모든 변수 ( "$ 1", "$ 2"...)를 인용하고 싶을 것입니다. (필자는 쉘 스크립팅 모범 사례이므로이 작업을 수행했습니다.)

/env/,/^[{space,tab}]*$/ 는 sed의 범위 주소입니다. 환경 설정이 들어있는 텍스트 블록을 읽습니다. 나는 당신의 샘플 입력이 정확하고 각각의 env가 공백 라인으로 분리되어 있다고 가정하고있다. 흠 ... 여기에는 파일의 마지막 부분이 포함됩니다.

** 편집하다**

이 답변으로 몇 가지 문제를 지적하기 위해 @posdef에 감사드립니다. 이 코드는 특정 경우를 해결하기 위해 업데이트됩니다.

수정 한 후에도, 다음과 같은 입력을 받았다는 것을 알았습니다.

   change_env.sh env2 prop2 "new value" file.yml

관련 출력은

     :prop2new value

따라서 extra : 및 space chars를 대체 문자로 하드 코딩하지 않아도되므로 <property> 값과 <new value> 를 호출하는 방법을 매우 자세하게 설명해야합니다. 즉

   change_env.sh env2 ":prop2: " "\"new value\"" file.yml
   # note extra cruft-^^-----^^^--^^---------^^--------------

관련 출력

env2:
  :prop1: "value1"
  :prop2: "new value"
  :prop3: "value3"
    ...
  :propn: "valuen"

IHTH


나는 awk를 사용할 것이다.

#!/bin/sh

if [ $# -ne 4 ]; then
    echo "usage: $0 env prop value file" >&2
    exit 1
fi

awk -F : -v env="$1" -v prop="$2" -v val=" \"$3\"" '
    BEGIN {OFS = FS}
    $1 == env {in_env = 1}
    NF == 0   {in_env = 0}
    in_env && $2 == prop {$3 = val}
    {print}
' "$4"

이 답변은 Glenn Jackman의 AWK 스크립트를 기반으로합니다. AWK 스크립트는 입력 테스트 유형에 내재 된 들여 쓰기 문제로 인해 테스트에 실패했습니다.

특히 원하는 환경에 있는지 여부를 확인하는 조건은 일반적으로 다른 행에 있기 때문에 원하는 속성이 있는지 여부를 확인하는 것과는 다른 반복에서 발생합니다. 따라서 in_env && $2 == prop 는 true property : value 반환하지 않습니다 property : value 이는 property : value 쌍이 별도의 줄에 $1 : $2 로 읽히는 것을 고려한 것입니다.

또한 비교 $2 == prop 는 선행 공백 문자로 인해 손질이 필요합니다. 스크립트를 사람이 읽을 수있게 만들기 위해 여기 에 설명 된 멋진 한 줄 짜기를 추가했습니다.

마지막으로 원래 스크립트는 새 값을 큰 따옴표로 하드 코딩하여 숫자 값을 삽입하는 경우 문제가됩니다.

테스트 케이스에서 잘 작동하는 다음과 같은 방법으로 스크립트를 수정했습니다. 다른 사람들에게 유용 할 경우에 대비하여 여기에 제공하고 있습니다.

#!/bin/sh

if [ $# -ne 4 ]; then
    echo "usage: $0 env prop value file" >&2
    exit 1
fi

awk -F : -v env="$1" -v prop="$2" -v val=" $3" '
    function ltrim(s) { sub(/^[ \t\r\n]+/, "", s); return s }
    function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s }
    function trim(s) { return rtrim(ltrim(s)); }
    BEGIN {OFS = FS}
    $1 == env {in_env = 1}
    NF == 0   {in_env = 0}
    in_env && trim($1) == prop {$2 = val}
    {print}  
' "$4"

적어도 하나의 선견지명이 필요합니다. 이를 수행하는 방법은 여러 가지가 있지만이를 파싱하는 방법을 알고있는 것을 사용해야합니다.

s/(\s*$env:\s*(?:(?!\s*[^\W_]+:)[^\n]*\s*)*\s*:$prop:[^\S\n]*")[^\n]*(")/$1$replacement$2/g

Perl로 약간 테스트 :

use strict;
use warnings;

my $str = '
env1:
  :prop1: "value1"
  :prop2: "value2"
        ...
  :propn: "valuen"

env2:
  :prop1: "value1"
        ...
  :prop2: "value2"
  :prop3: "value3"
  :propn: "valuen"
    ...

envn:
  :prop1: "value1"
        ...
  :prop3: "value3"
  :propn: "valuen"
';

my ($env, $prop, $replacement) = ('(?:env2|envn)', 'prop1', 'this changed');

if ( $str =~ s/
    (
      \s*$env:\s*
      (?: (?!\s*[^\W_]+:) [^\n]*\s* )*
      \s*:$prop:[^\S\n]*
      "
    ) [^\n]*
    ( " )
  /$1$replacement$2/xg )
{
     print "Found it!\n";
     print $str;
}

산출:

Found it!

env1:
  :prop1: "value1"
  :prop2: "value2"
        ...
  :propn: "valuen"

env2:
  :prop1: "this changed"
        ...
  :prop2: "value2"
  :prop3: "value3"
  :propn: "valuen"

    ...

envn:
  :prop1: "this changed"
        ...
  :prop3: "value3"
  :propn: "valuen"




sed