sed가 대체 문자열을 해석하지 못하게하는 방법이 있습니까? [닫은]

sed를 사용하여 키워드를 문자열로 바꾸려면 sed가 대체 문자열을 해석하려고 시도합니다. 대체 문자열에 sed 문자가 ‘/’문자와 같이 특수한 것으로 간주되는 경우, 대체 문자열에 sed의 작동 방법을 알려주는 문자가없는 경우에는 실패합니다.

전의:

VAR="hi/"

sed "s/KEYWORD/$VAR/g" somefile

특수 문자의 대체 문자열을 해석하지 않도록 sed에 지시하는 방법이 있습니까? 내가 원하는 것은 파일의 키워드를 변수의 내용과 상관없이 변수의 내용으로 바꾸는 것입니다.



답변

sed 대신 -p(Loop over input) 및 -e(명령 줄에 프로그램 제공 ) 대신 Perl을 사용할 수 있습니다 . Perl을 사용하면 쉘에서 변수 보간 하지 않고 환경 변수에 액세스 할 수 있습니다 . 변수를 내 보내야합니다 .

export VAR='hi/'
perl -p -e 's/KEYWORD/$ENV{VAR}/g' somefile

어디에서나 변수를 내 보내지 않으려면 해당 프로세스에만 변수를 제공하십시오.

PATTERN="$VAR" perl -p -e 's/KEYWORD/$ENV{PATTERN}/g' somefile

Perl의 정규 표현식 구문은 기본적으로 sed와 약간 다릅니다.


답변

교체 부분 \에는 &,, 개행 및 구분 기호 ( ref ) 와 같은 4 개의 특수 문자 만 있습니다.

$ VAR='abc/def&ghi\foo
next line'

$ repl=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"$VAR")

$ echo "$repl"
abc\/def\&ghi\\foo\
next line

$ echo ZYX | sed "s/Y/$repl/g"
Zabc/def&ghi\foo
next lineX


답변

여전히 대부분의 변수 값을 올바르게 처리하는 가장 간단한 해결책은 인쇄 sed명령 이 아닌 문자를 대체 명령의 구분 기호로 사용하는 것 입니다.

에서 vi당신이 입력 Ctrl 키-V에 의한 제어 문자를 탈출 할 수 (더 일반적으로 작성 ^V). 따라서 일부 제어 문자를 사용하는 경우 ( ^A이 경우에는 종종 구분 기호로 사용 ) sed드롭하지 않는 변수에 인쇄되지 않는 문자가있는 경우에만 명령이 중단됩니다.

그래서 당신은 입력 "s^V^AKEYWORD^V^A$VAR^V^Ag"하고 당신이 얻는 것 ( vi)은 다음과 같습니다 :

sed "s^AKEYWORD^A$VAR^Ag" somefile

$VAR비 인쇄 문자를 포함하지 않는 한 작동 합니다 ^A.


물론, 사용자 입력 을의 값으로 전달하는 경우 $VAR모든 베팅이 해제되어 일반 사용자에게 입력하기 어려운 제어 문자에 의존하는 대신 입력을 철저히 정리하는 것이 좋습니다.


그러나 실제로 구분 기호 문자열보다 더 조심해야합니다. 예를 들어, &대체 문자열에있는 경우 “일치 한 전체 텍스트”를 의미합니다. 예를 들어, s/stu../my&/“stuff”를 “mystuff”로 바꾸고 “stung”을 “mystung”으로 바꿀 것입니다. 따라서 변수에 대체 문자열로 삽입 할 문자 가있을 있지만 리터럴을 사용하려는 경우 변수 값만 사용하는 경우에서 데이터를 대체 문자열로 사용하려면 먼저 데이터를 삭제해야합니다 sed. (데이터 삭제는 sed또한 가능합니다 .)


답변

대신 a ,또는 a |를 사용할 수 있으며 분리기로 사용하고 기술적으로는 아무것도 사용할 수 있습니다.

맨 페이지에서

\cregexpc
           Match lines matching the regular expression regexp.  The  c  may
      be any character.

보시다시피 처음에 구분 기호 앞에 \로 시작하면 구분 기호로 사용할 수 있습니다.

http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command 문서에서 :

The / characters may be uniformly replaced by any other single character 
within any given s command.

The / character (or whatever other character is used in its stead) can appear in 
the regexp or replacement only if it is preceded by a \ character.

예:

sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"

echo "Hello/ World" | sed "s,Hello/,Neo,"


답변

줄 기반이고 바꿀 줄이 하나 뿐인 경우을 사용하여 파일 자체를 교체 줄 앞에 추가하고 printf첫 번째 줄을 sed보류 공간 에 저장하고 필요에 따라 삭제하는 것이 좋습니다. 이렇게하면 특수 문자에 대해 전혀 걱정할 필요가 없습니다. (여기서 유일한 가정은 $VAR줄 바꿈없이 한 줄의 텍스트 를 포함 한다는 것입니다 . 이미 주석에서 말한 내용입니다.) 줄 바꿈 외에 VAR은 무엇이든 포함 할 수 있으며 관계없이 작동합니다.

VAR=whatever
{ printf '%s\n' "$VAR";cat somefile; } | sed '1{h;d;};/KEYWORD/g'

printf '%s\n'내용에 $VAR관계없이 리터럴 문자열로 내용을 인쇄 한 다음 줄 바꿈을합니다. ( echo예를 들어 $VAR하이픈 으로 시작 하는 내용과 같은 경우에는 다른 작업을 수행 합니다 echo. 에 전달되는 옵션 플래그로 해석됩니다 .)

중괄호는 출력 printf내용이에 somefile전달 될 때 내용 앞에 추가하는 데 사용 됩니다 sed. 닫는 중괄호 앞의 세미콜론과 마찬가지로 중괄호 자체를 분리하는 공백이 중요합니다.

1{h;d;};A와 sed명령은 텍스트의 첫 줄을 저장할 sed보류 공간 , 후 d(오히려 인쇄보다는) 라인을 elete.

/KEYWORD/를 포함하는 모든 행에 다음 조치를 적용합니다 KEYWORD. 동작은 g기타로, 홀드 공간의 내용을 가져 와서 패턴 공간 대신 , 즉 현재 행 전체를 삭제합니다. (이것은 라인의 일부만 교체하기위한 것이 아닙니다 .) 보류 공간은 비워지지 않으며 패턴 공간으로 복사 되어 존재하는 모든 것을 대체합니다.

정규식 을 고정 하여 KEYWORD 만 포함 하는 줄과 일치하지 않고 KEYWORD 이외의 줄에 아무것도없는 줄만 일치 시키려면 줄의 시작 부분 앵커 ( ^)와 줄의 끝 앵커 ( $)를 정규식 :

VAR=whatever
{ printf '%s\n' "$VAR";cat somefile; } | sed '1{h;d;};/^KEYWORD$/g'


답변

Bash의 패턴 대체 매개 변수 확장을 사용하여 대체 문자열에서 슬래시를 백 슬래시 이스케이프 할 수 있습니다. Bash를 위해 슬래시를 이스케이프해야하기 때문에 약간 지저분합니다.

$ var='a/b/c';var="${var//\//\\/}";echo 'this is a test' | sed "s/i/$var/g"

산출

tha/b/cs a/b/cs a test

당신은 할 수 귀하의 SED 명령에 직접 매개 변수 확장을 넣어 :

$ var='a/b/c';echo 'this is a test' | sed "s/i/${var//\//\\/}/g"

하지만 첫 번째 형식은 좀 더 읽기 쉽다고 생각합니다. 물론 여러 sed 명령에서 동일한 대체 패턴을 재사용하려는 경우 변환을 한 번만 수행하는 것이 좋습니다.

또 다른 옵션은 awk, perl 또는 Python으로 작성된 스크립트 또는 C 프로그램을 사용하여 sed를 사용하는 대신 대체 작업을 수행하는 것입니다.


다음은 교체 할 키워드가 입력 파일의 완전한 줄 (줄 바꿈 제외) 인 경우 작동하는 Python의 간단한 예입니다. 보시다시피, 기본적으로 Bash 예제와 동일한 알고리즘이지만 입력 파일을보다 효율적으로 읽습니다.

import sys

#Get the keyword and replacement texts from the command line
keyword, replacement = sys.argv[1:]
for line in sys.stdin:
    #Strip any trailing whitespace
    line = line.rstrip()
    if line == keyword:
        line = replacement
    print(line)


답변

이것이 내가 갔던 방법입니다.

#Replaces a keyword with a long string
#
#This is normally done with sed, but sed
#tries to interpret the string you are
#replacing the keyword with too hard
#
#stdin - contents to look through
#Arg 1 - keyword to replace
#Arg 2 - what to replace keyword with
replace() {
        KEYWORD="$1"
        REPLACEMENT_STRING="$2"

        while IFS= read -r LINE
        do
                if [[ "$LINE" == "$KEYWORD" ]]
                then
                        printf "%s\n" "$REPLACEMENT_STRING"
                else
                        printf "%s\n" "$LINE"
                fi
        done < /dev/stdin
}

내 키워드가 자체적으로 줄에 있기 때문에 이것은 내 경우에 효과적입니다. 키워드가 다른 텍스트와 일치하면 작동하지 않습니다.

내 솔루션을 코딩하지 않는 쉬운 방법이 있는지 알고 싶습니다.