GNU 또는 BSD Sed의 정규식 대체 / 또는 연산자 (foo | bar)


28

나는 그것을 작동시킬 수 없다. GNU sed 문서는 파이프를 탈출한다고 말했지만 작동하지 않으며 탈출하지 않고 직선 파이프를 사용하지 않습니다. Parens를 추가해도 아무런 차이가 없습니다.

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog

답변:


33

기본적으로sed 대체 연산자를 포함하지 않는 POSIX 기본 정규 표현식을 사용합니다 |. sedGNU 및 FreeBSD를 포함한 많은 버전은 확장을 포함하는 확장 정규 표현식 으로의 전환을 지원 |합니다. 사용 방법은 다양합니다 : GNU sed는 사용-r 하고 FreeBSD , NetBSD , OpenBSDOS X는 사용 -E합니다. 다른 버전은 대부분 전혀 지원하지 않습니다. 당신이 사용할 수있는:

echo 'cat dog pear banana cat dog' | sed -E -e 's/cat|dog/Bear/g'

BSD 시스템 sed -r과 GNU에서 작동합니다.


GNU sed는 완전히 문서화되지 않았지만에 대한 작업을 지원하는 것으로 보이 -E므로 위와 같이 다중 플랫폼 스크립트가있는 경우 이것이 최선의 선택입니다. 문서화되어 있지 않기 때문에 실제로는 신뢰할 수 없습니다.

의견에 따르면 BSD 버전 -r은 문서화되지 않은 별칭으로도 지원 됩니다. OS X는 여전히 현재는 아니고 이전 NetBSD 및 OpenBSD 컴퓨터도 액세스 할 수 없지만 NetBSD 6.1은 그렇지 않습니다. 내가 보편적으로 도달 할 수있는 상업적 Unices는 그렇지 않습니다. 따라서 이식성 문제는이 시점에서 상당히 복잡해졌지만 간단한 대답은 필요할 때 전환awk 하는 것인데, 어디서나 ERE를 사용합니다.


언급 한 세 가지 BSD는 모두 GNU sed와의 호환성 -r-E대한 동의어로 옵션을 지원합니다 . OpenBSD와 OS X sed -E은 이스케이프 된 파이프를 대체 연산자가 아닌 리터럴 파이프로 해석합니다. 여기에 작동 링크의 는 NetBSD 매뉴얼 페이지는 그리고 여기에 하나 열살없는 오픈 BSD합니다.
damien



9

(a|b)기본 정규 표현식이 아닌 확장 정규 표현식 이기 때문에 발생합니다 . -E이 문제를 해결 하려면 옵션을 사용하십시오 .

echo 'cat
dog
pear
banana
cat
dog'|sed -E 's/cat|dog/Bear/g'

로부터 sed매뉴얼 페이지

 -E      Interpret regular expressions as extended (modern) regular
         expressions rather than basic regular expressions (BRE's).

-r같은 일에 대한 또 다른 플래그이지만, -E더 휴대용 심지어는 POSIX 사양의 다음 버전에있을 것입니다.


6

이 작업을 수행하는보다 효율적인 방법은 주소를 사용하는 것입니다. 당신은 이것을 할 수 있습니다 :

printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b' -e '};cBear'

이러한 방식으로 줄에 문자열 cat 이없고 문자열 dog 문자열 sed b이 스크립트에서 빠져 나오지 않으면 현재 줄을 자동 인쇄하고 다음 줄을 당겨 다음 사이클을 시작합니다. 따라서 다음 명령을 수행하지 않습니다.이 예 c에서는 Bear 를 읽기 위해 전체 행을 걸지만 아무 것도 할 수 있습니다.

!b해당 sed명령 에서 다음에 나오는 명령문 은 문자열을 포함하는 행 에서만 일치 dog하거나 cat-일치하지 않는 행을 일치시킬 위험없이 추가 테스트를 수행 할 수 있습니다. 이제 규칙을 적용 할 수 있습니다. 한 쪽 또는 다른쪽에 만.

그러나 다음입니다. 위 명령의 출력 결과는 다음과 같습니다.

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

역 참조로 룩업 테이블을 이식 가능하게 구현할 수도 있습니다.

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'

이 간단한 예제에서는 설정 작업이 훨씬 많지만 sed장기적으로 훨씬 더 유연한 스크립트를 만들 수 있습니다 .

첫 번째 줄에서 x홀드 스페이스와 패턴 스페이스를 변경 한 다음 문자열 <space>고양이 <space>도그<space> 를 홀드 스페이스에 삽입 한 다음 x다시 변경합니다.

그때부터 모든 다음 줄 G에서 패턴 공간에 추가 된 공간을 유지하고 마지막에 방금 추가 한 줄 바꿈까지 줄의 시작 부분에서 모든 문자가 그 뒤에 공백으로 둘러싸인 문자열과 일치하는지 확인하십시오. 그렇다면 나는 전체 로트를 Bear로 교체하고 P패턴 공간에서 처음 나타나는 개행 d까지만 찢어 버리고 해를 끼치 지 않으면 해를 끼치 지 않습니다 .

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

그리고 내가 유연하다고 말할 때, 나는 그것을 의미합니다. 여기가 대체 고양이BrownBearBlackBear :

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'

###OUTPUT###
BrownBear
BlackBear
pear
banana
BrownBear
BlackBear

물론 룩업 테이블의 내용을 크게 확장 할 수 있습니다 . 90 년대에 Greg Ubben의 유즈넷 이메일에서 주제에 대한 아이디어를 얻었 습니다 sed s///.


1
휴, +1. 당신은 내가 말해야 할 상자 밖에서 생각하는 것에 대한 생각을 가지고 있습니다
iruvar

@ 1_CR-내 생각이 아닌 나의 마지막 편집을 보아라. 나는 그것을 인정하지 않으며 칭찬이라고 생각하지 않는다. 그러나 기한이 지난 곳을 신용하고 싶습니다.
mikeserv

1

이것은 매우 오래된 질문이지만 누군가가 시도하고 싶을 경우 sed 파일로 sed 에서이 작업을 수행하는 상당히 낮은 노력 방법이 있습니다. 각 옵션은 별도의 행에 나열 될 수 있으며 sed는 각 옵션을 평가합니다. 논리적으로 or와 같습니다. 예를 들어 특정 코드가 포함 된 줄을 제거하려면

당신은 말할 수 있습니다 : sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'

또는 이것을 sed 파일에 넣으십시오.

/^\/\*!40103.*\/;$/d
/^\/\*!40101.*\/;$/d
/^\/\*!40111.*\/;$/d

0

여기에 어떤 구현 특정 옵션을 사용하지 않는 기술이다 sed(예를 들어 -E, -r). 패턴을 단일 정규식으로 설명하는 대신 cat|dog간단히 sed두 번 실행할 수 있습니다 .

echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat/Bear/g' | sed 's/dog/Bear/g'

실제로 확실한 해결 방법이지만 공유 할 가치가 있습니다. 매우 긴 체인은보기에 sed좋지 않지만 자연스럽게 두 개 이상의 패턴 문자열로 일반화됩니다 .

sed -i파일을 변경하기 위해 종종 (모든 구현에서 동일하게 작동) 사용 합니다. 여기에는 각 임시 결과가 파일에 저장되므로 패턴 문자열의 긴 목록이 멋지게 통합 될 수 있습니다.

for pattern in cat dog owl; do
    sed -i "s/${pattern}/Bear/g" myfile
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.