sed: 구성 블록의 여러 줄 교체

sed: 구성 블록의 여러 줄 교체

기본적으로 다음과 같은 구성 파일이 있습니다.

(...content...)
# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY
(... more content ...)
# END DYNAMIC BLOCK
(... even more content ...)

이제 bash 에서 이를 사용하여 CONTENT=`wget -O - http://$SERVER/get_config.php`동적 블록을 대체했습니다.

이제 대체 작업을 수행하는 방법과 해당 블록이 존재하지 않는 경우 파일 끝에 해당 블록을 삽입하는 스크립트를 얻는 방법은 무엇입니까?

답변1

sed를 사용하려면 명명된 파이프에서 읽을 수 있습니다. 이 코드는 오류를 처리하려고 시도하지 않습니다. 동적 블록 헤더가 여러 번 나타나면 스크립트가 차단됩니다.

CONTENT_URL="http://$SERVER/get_config.php"
tmp=$(mktemp -d)
(
  cd "$tmp"
  mkfifo dynamic_seen dynamic_content
  : >dynamic_seen & seen_pid=$!
  wget -O dynamic_content "$CONTENT_URL" & wget_pid=$!
  sed -e '/^# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY$/ p' \
      -e '/^# END DYNAMIC BLOCK$/ {'
          -e p -e 'r dynamic_seen' -e 'r dynamic_content' -e '}' \
      -e '/^# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY$/, /^# END DYNAMIC BLOCK$/ d'
  if ! kill $dynamic_seen 2>/dev/null; then
    # The pipe hasn't been read, so there was no dynamic block. Add one.
    echo "# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY"
    cat dynamic_pipe
    echo "# END DYNAMIC BLOCK - DO NOT EDIT MANUALLY"
  fi
)
rm -rf "$tmp"

하지만 저는 awk를 선택하겠습니다.

export CONTENT_URL="http://$SERVER/get_config.php"
awk '
    $0 == "# END DYNAMIC BLOCK - DO NOT EDIT MANUALLY" {skip=0; system("wget \"$CONTENT_URL\""); substituted=1}
    !skip {print}
    $0 == "# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY" {skip=1}
    END {
         if (!substituted) {
            print "# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY";
            system("wget \"$CONTENT_URL\"");
            print "# END DYNAMIC BLOCK - DO NOT EDIT MANUALLY";
        }
    }
'

답변2

다음과 같이 서브쉘과 두 개의 sed 명령을 사용합니다.

beg_tag='# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY'
end_tag='# END DYNAMIC BLOCK'

(
  sed "/^$beg_tag"'$/,$d' oldconf
  echo "$beg_tag"
  wget -O - http://$SERVER/get_config.php
  echo "$end_tag"
  sed "1,/^$end_tag/d" oldconf
) > newconf

beg_tag합계 에 sed의 중요한 문자를 넣지 않도록 주의하세요 end_tag.

태그가 없으면 출력이 추가됩니다. 첫 번째 sed 명령은 입력에서 어떤 줄도 삭제하지 않으며 두 번째 sed 명령은 모든 줄을 삭제합니다.

시험

다음이 포함된 경우 oldconf:

(...content...)
# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY
(... more content ...)
# END DYNAMIC BLOCK
(... even more content ...)

그리고 wget 명령은 로 대체되며 echo hello world출력은 다음과 같습니다.

(...content...)
# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY
hello world
# END DYNAMIC BLOCK
(... even more content ...)

이제 해당 블록을 제거하면 다음 입력을 사용합니다.

(...content...)
(... even more content ...)

출력은 다음과 같습니다

(...content...)
(... even more content ...)
# BEGIN DYNAMIC BLOCK - DO NOT EDIT MANUALLY
hello world
# END DYNAMIC BLOCK

답변3

이것은 sed실제로 매우 간단합니다. 행과 앵커 사이의 범위 균형을 EOF로 조정하면 됩니다.

INPUT |
sed -e 's/\\/&&/g;$!s/$/\\/' |        #this sed escapes INPUT for scripting
sed -e '/^'"$START"'/,$!{$!b          #this sed applies concatenated scripts
             G;G;s/$/'"$END"'/;P;:n
};$!N;  /\n'"$END"'/,$!{G;$!bn
};      /\n\n/c\' -f - -e 'P;$d;D
' ./named_infile >outfile

따라서 몇 가지 일이 진행되고 있지만 그 중 가장 중요한 것은 다음과 같습니다.

/^$START/,$!{ -- function --}
N; /\n$END/,$!{ -- function -- }

아이디어는 우리가라인 범위는 Line 1이거나 $기본적으로 방금 끝났습니다.탐욕스러운. 일반적으로 행 범위는 가능한 가장 작은 행 하위 집합에만 적용됩니다. 각 LHS 일치부터 시작하여 입력에서 다음에 발생하는 첫 번째 RHS 일치로 끝납니다. RHS가 EOF인 경우에는 하나만 적용할 수 있습니다. 왜냐하면 RHS가 EOF이기 때문입니다.

내가 할 때 :

/^$START/,$!{ -- function -- }

중괄호 사이의 모든 코드가 infile의 모든 줄에 대해 실행되도록 지정했지만아니요포함하다 $START. 이 함수 컨텍스트에서는 b마지막 행이 아닌 모든 행을 확장합니다.!$

이렇게 하면 입력의 첫 번째 줄 앞의 모든 줄이 $START자동으로 인쇄되고 무시됩니다. 그러나 $마지막 줄이 이 범위 내에 있으면(한 번도 나타나지 않을 수 있으므로 ) 꼬치에 문자를 $START연결할 준비가 된 것입니다 .c

따라서 범위가 입력에 나타나지 않으면 INPUT이 파일 끝에 추가됩니다.

다음에 내가 이렇게 할 때:

N; /\n$END/,$!{ -- function -- }

이번에도 컨텍스트에 따라 함수를 적용합니다. 이번에는 범위 본문에 적용되며 입력이 처음으로 나타나는 경우에만 적용됩니다. 왜냐하면 의 보수는 첫 번째 발생 전에 정렬되지 않은 모든 행 /\n$END/,$이고 다음 발생까지만 적용되지만 다음 발생은 포함하지 않기 때문입니다.b$START$END

이 경우 적용되는 함수는 분기 루프입니다. 입력이 범위 내에 있는 한 첫 번째 일치를 찾을 때까지 계속 역추적 b하고 확장 줄을 끌어오고 , 이 시점에서 표준 입력 스크립트 파일 에 대한 전체 범위를 일시 중지합니다. - 또는 이스케이프된 입력. 첫 번째 일치 이전에 마지막 줄이 발생하면 마지막 줄에도 동일한 규칙이 적용됩니다.N$ENDc-f -$START

그게 다야. 하지만 이 작업에는 특별한 파일이 필요하지 않습니다.(안전하게)사본을 포함하다입력하다필요할 때 적용하기 위해 스크립트 내에서 r언제든지 작성할 필요가 없습니다.

관련 정보