저는 CentOS Bash 환경에서 작업하고 있으며 sed
전문 시스템 관리자가 아닌 사람으로서 sed
약간 "혼란스러울" 정도로 긴 명령을 가지고 있으며 적어도 2년에 한 번씩, 적어도 긴 명령으로 사용합니다.
read new_email_address
sed -i 's/$to = ".*";$/$to = "'"$new_email_address"'";/' FILE
sed
명령을 다음과 같은 중첩 의사코드로 나누고 싶습니다 .
sed -i
'
s/
$to = ".*";$
/
$to = "'"$new_email_address"'";
/g
'
FILE_PATH
답변1
여기서는 이것을 사용하겠습니다 perl
. -i
비표준 옵션이므로 일부 sed
구현에서는 이를 복사했지만 perl
이식 가능하지 않습니다. 이 방법을 사용하는 것도 sed
명령 주입 취약점입니다. 내용이 $new_email_address
결국 sed
코드로 해석되기 때문입니다(GNU 언어에는 해당 프롬프트에 입력을 sed
시도하는 등 임의의 명령을 실행할 수 있는 명령이 있습니다 )./;ereboot;#
read
IFS= read -r new_email_address
REPLACEMENT="$new_email_address" perl -pi -e '
s{
(\$to \s* = \s* ") .* (" \s* ; \s* )$
}{$1$ENV{REPLACEMENT}$2}gx
' FILE
존재하다perl
s{...}{...}flags
extra 를 사용하면s/.../.../flags
일치하는 쌍을 더 쉽게 확인할 수 있습니다(그리고 일치하는 한 내부 사용도 허용합니다){
.}
- 이
x
플래그를 사용하면 정규식 내부에 공백(또는 주석)을 추가하여 읽기 쉽게 만들 수 있습니다(이러한 공백은 정규식의 일부가 아니지만\s*
임의 개수의 공백과 일치합니다). &
환경 변수를 통해 , , 백슬래시 또는 개행 문자가 포함된 문자열을 전달하는 경우에도 대체에 임의의 문자열을 안전하게 사용할 수 있습니다 ./
-C
//-Mlocale
...-Mopen=locale
옵션을 사용하지 않는 한perl
바이트 수준에서 작업하므로.*
입력이 로케일에서 유효한 텍스트를 형성하지 않는 경우에도 일치에 실패하지 않습니다.- 일부
sed
구현 과 달리perl
줄 길이(사용 가능한 메모리 제외)에는 제한이 없으며 NUL 바이트를 포함하거나 개행 문자로 끝나지 않는 입력을 차단하지 않습니다.
교체 부품에도 공백을 허용하려면 e
교체 부품이 코드가 되도록 하는 플래그를 추가할 수 있습니다 perl
.
REPLACEMENT="$new_email_address" perl -pi -e '
s{
(\$to \s* = \s* ") .* (" \s* ; \s* )$
}{
$1 . $ENV{REPLACEMENT} . $2
}gxe
' FILE
예를 들어. 또한 read
설정 없이 $IFS
및 없이 를 사용하는 것은 -r
거의 의미가 없다는 점을 기억하십시오.
답변2
더 읽기 쉬운지는 확실하지 않지만 sed
먼저 빌드 표현식을 사용한 printf
다음 다음과 함께 사용할 수 있습니다 sed
.
sed_expr=$(printf 's/$to = ".*";$/$to = "%s";/' "$new_email_address")
sed -i "$sed_expr" FILE
제 생각에는 이렇게 하면 sed의 전반적인 기능과 입력이 어떤 역할을 하는지 이해하기가 더 쉽습니다.
답변3
인용된 명령은 다음과 같습니다.나는 최근 답변에 썼다.(추가됨 -i
):
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
이는 sed
단일 편집 명령으로 호출됩니다. 표현식에 사용되는 명령 은 대체를 수행하는 명령 sed
입니다 s
. 즉, 정규 표현식과 일치하는 것을 다른 것으로 바꿉니다.
이 명령의 일반적인 형식 s
은 입니다 range s/pattern/replacement/flags
. 여기서 다루는 명령에는 표현 range
이 없습니다.s
모두입력 텍스트의 행) 및 no 입니다 flags
. 따라서 sed
일반 양식에 편집 스크립트가 있습니다.
s/pattern/replacement/
명령에서 볼 수 있듯이 비트 pattern
는 다음과 같습니다.
$to = ".*";$
$to = "
이 패턴은 뒤에 오는 리터럴 텍스트와 일치합니다.아무것(길이에 상관없이 모든 문자의 시퀀스), 그 뒤에 리터럴 텍스트가 옵니다 ";
. $
at the end는 마지막 숫자가 ";
줄의 맨 끝에서 일치하도록 강제합니다.
그리고 우리는 그것을 가지고 있습니다 replacement
.
쉘 변수의 값에 따라 달라지는 것으로 대체하고 싶기 때문에 잠시 동안 작은따옴표로 묶인 문자열(즉, 표현식)에서 벗어나야 합니다 sed
. 우리는 이것을 한 후에
$to = "
교체 중입니다. 쉘 변수의 값은 new_email_address
삽입되고 큰따옴표로 올바르게 인용되므로 쉘은 이를 공백으로 분할하거나 해당 값에 대해 파일 이름 글로빙을 수행하지 않습니다.
값을 삽입한 후 다음 명령으로 명령 replacement
섹션을 종료합니다.s
";
이는 전체 replacement
필드 이며 $to = "
그 뒤에 일부 값(새 이메일 주소)과 가 옵니다 ";
.
따라서 명령의 각 비트가 수행하고 의미하는 바를 분석하고 명확하게 설명합니다.
명령 구조 sed
:
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
s/ pattern / replacement /
sed
셸에서 표현식을 구성하는 문자열 비트:
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^
single-quoted string double-quoted final single-quoted bit
string for shell
variable expansion
위의 내용을 좀 더 도식적으로
sed 'something here'"$variable_value_here"'ending here' file
비트 something here
는 큰따옴표로 끝나고, ending here
비트는 큰따옴표로 시작됩니다.
답변4
따옴표를 구분하여 유지하는 한 가지 방법은 여러 -e sed 코드를 사용하여 검색과 바꾸기를 분리하여 sed 명령을 중단하는 것입니다.
q=\"; # a double quote character
sed -i \
-e '/$to = ".*";$/c\' \
-e "\$to = $q$new_email_address$q;" \
FILE
sed -i \
-e '/$to = ".*";$/!b' \
-e "s//\$to = $q$new_email_address$q;/" \
FILE;