Bash 환경에서 sed 명령을 중첩된 부분으로 나누는 방법은 무엇입니까?

Bash 환경에서 sed 명령을 중첩된 부분으로 나누는 방법은 무엇입니까?

저는 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{...}{...}flagsextra 를 사용하면 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;

관련 정보