기본적으로 다음과 같은 구성 파일이 있습니다.
(...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
$END
c
-f -
$START
그게 다야. 하지만 이 작업에는 특별한 파일이 필요하지 않습니다.(안전하게)사본을 포함하다입력하다필요할 때 적용하기 위해 스크립트 내에서 r
언제든지 작성할 필요가 없습니다.