!["sed" 대체에 삽입된 문자열이 모든 메타 문자를 이스케이프하는지 확인하는 방법](https://linux55.com/image/35044/%22sed%22%20%EB%8C%80%EC%B2%B4%EC%97%90%20%EC%82%BD%EC%9E%85%EB%90%9C%20%EB%AC%B8%EC%9E%90%EC%97%B4%EC%9D%B4%20%EB%AA%A8%EB%93%A0%20%EB%A9%94%ED%83%80%20%EB%AC%B8%EC%9E%90%EB%A5%BC%20%EC%9D%B4%EC%8A%A4%EC%BC%80%EC%9D%B4%ED%94%84%ED%95%98%EB%8A%94%EC%A7%80%20%ED%99%95%EC%9D%B8%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95.png)
텍스트 스트림을 읽고 나중에 사용할 수 있도록 sed 명령 파일을 생성하는 스크립트가 있습니다 sed -f
. 생성된 sed 명령은 다음과 같습니다.
s/cid:image002\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1922/g
s/cid:image003\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1923/g
s/cid:image004\.jpg@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1924/g
명령을 생성하는 스크립트가 다음 sed
과 같다고 가정합니다.
while read cid fileid
do
cidpat="$(echo $cid | sed -e s/\\./\\\\./g)"
echo 's/'"$cidpat"'/https:\/\/mysite.com\/files\/'"$fileid"'/g' >> sedscr
done
cid
문자열의 모든 정규식 메타 문자가 올바르게 이스케이프되고 보간 되도록 스크립트를 개선하려면 어떻게 해야 합니까 ?
답변1
사용할 이스케이프 변수왼쪽그리고오른쪽s
명령 에 대해 sed
(여기 $lhs
및 $rhs
각각) 다음을 수행합니다.
escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\\/.^$*]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\\/&]:\\&:g; $!s/$/\\/')
sed "s/$escaped_lhs/$escaped_rhs/"
줄 바꿈 은 $lhs
포함될 수 없습니다.
즉, LHS에서는 모든 정규식 연산자( ][.^$*
), 이스케이프 문자 자체( ) \
및 구분 기호( /
)가 이스케이프됩니다.
&
RHS에서는 이스케이프 , 구분 기호, 백슬래시 및 개행( $!s/$/\\/
마지막 줄( )을 제외한 모든 줄의 끝에 백슬래시를 삽입하여 달성) 만 필요합니다 .
참고: 문자 앞에 백슬래시를 추가하고 싶지는 않습니다.아니요특별한 의미가 있습니다. 왜냐하면 이렇게 하면 결국주다특별한 의미가 있습니다. 예를 들어, <
, +
및 는 t
BRE에서 특별한 의미가 없지만, \<
, \+
및 (및 RHS를 포함한 for )는 \t
일부 구현에서 특별한 의미를 갖습니다.sed
\t
/
명령에서 구분 기호로 사용 sed
s
하고 활성화하지 않는다고 가정합니다 .확장된 RE-r
(GNU sed
// ssed
/ ast
) 또는 (BSD, 가장 가까운 GNU, 가장 가까운 비지박스) busybox sed
또는-E
ast
PCRE( -R
) ssed
또는RE 강화-A
/ -X
( ) 처럼 ast
추가 RE 연산자가 있습니다.
ERE(이러한 확장 중 가장 널리 지원되는 확장)의 경우 해당 기능은 다음과 같습니다.
escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\\/.^$*+?(){}|]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\\/&]:\\&:g; $!s/$/\\/')
sed -E "s/$escaped_lhs/$escaped_rhs/"
임의의 데이터로 작업할 때의 몇 가지 기본 규칙은 다음과 같습니다.
- 사용하지 마세요
echo
- 변수 참조
- 로캘(특히 문자 집합)의 영향을 고려하세요.도망가다
sed
sed
명령은 명령과 동일한 로캘에서 실행됩니다.사용이것탈출하다sed
예: 문자열(동일한 명령 사용) $lhs
개행 문자를 잊지 마세요(여기서 개행 문자가 포함되어 있는지 확인하고 조치를 취할 수 있습니다).
더 안전한 옵션은 환경에 문자열을 전달하는 perl
대신 / 정규식 연산자를 사용하여 문자열을 문자 그대로 가져오는 것입니다.sed
\Q
\E
perl
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl
(기본적으로)은 로캘 문자 집합의 영향을 받지 않습니다. 위에서는 문자열을 바이트 배열로만 처리하고 사용자에게 표시할 수 있는 문자(있는 경우)에 대해서는 신경 쓰지 않기 때문입니다. 를 사용하면 모든 명령 sed
의 로케일을 with 로 수정하여 C
동일한 결과를 얻을 수 있습니다. 단, 이는 오류 메시지의 언어에도 영향을 미칩니다.LC_ALL=C
sed
일부 셸에서는 외부 유틸리티를 사용하지 않고도 탈출할 수도 있습니다.
zsh
(BRE 이스케이프의 경우 여기) :
set -o extendedglob
escaped_lhs=${lhs//(#m)[][\\.^$\/&]/\\$MATCH}
escaped_rhs=${rhs//(#m)[\\&\/$'\n']/\\$MATCH}
존재하다 ksh93
:
escaped_lhs=${lhs//[][\\.^$\/&]/\\\0}
escaped_rhs=${rhs//[\\&\/$'\n']/\\\0}
3.4.0+ 에서 fish
:
set escaped_lhs (
string replace -ar -- '[][\\\\/.^$*]' '\\\\$0' "$lhs" |
string collect --allow-empty
)
set escaped_rhs (
string replace -ar -- '[\\\\&/'\n']' '\\\\$0' "$rhs" |
string collect --allow-empty --no-trim-newlines
)