sed
BSD / macOS Sed 대 GNU Sed 대 POSIX Sed 스펙
수색…
소개
@ SnoringFrog의 주제 생성 요청에서 인용하려면 :
"sed를 사용하는 가장 큰 장애물 중 하나는 스크립트가 하나가 아닌 다른 스크립트가 아니기 때문에 실패 (또는 예기치 않은 방식으로 성공)하는 스크립트입니다. 더 큰 차이점을 단순하게 제거하면 좋을 것입니다."
비고
macOS 는 BSD 버전의 sed
[1] 를 사용하는데, 이것은 리눅스 배포판에 포함 된 GNU sed
버전과 많은면에서 다릅니다.
그들의 공통 분모 는 POSIX에 의해 선언 된 기능입니다 : POSIX sed
spec을보십시오.
가장 이식 가능한 접근 방식 은 기능을 제한 하는 POSIX 기능 만 사용 하는 것입니다 .
특히, POSIX는 제한이 많은 기본 정규 표현식 (예 :
|
(변경)에 대한 지원이 전혀없고,+
및?
대한 직접적인 지원이 없음) 및 다른 이스케이프 요구 사항에 대해서만 지원을 지정합니다.- 주의 사항 : GNU
sed
(-r
없이) 는\|
지원합니다. ,\+
및\?
POSIX와 호환되지 않습니다. 비활성화하려면--posix
를 사용 하십시오 (아래 참조).
- 주의 사항 : GNU
POSIX 기능 만 사용하려면
(두 버전 모두) :
-n
및-e
옵션 만 사용하십시오 (특히 확장 정규 표현식에 대한 지원을 사용하려면-E
또는-r
을 사용하지 마십시오)GNU
sed
: POSIX 전용 기능을 보장하기 위해--posix
옵션을 추가하십시오 (꼭 필요하지는 않지만, 주의 하지 않고 비 POSIX 기능을 우연히--posix
있습니다 .) :--posix
자체 는 POSIX 호환이 아닙니다. )POSIX 전용 기능을 사용하면 더 엄격한 포맷팅 요구 사항을 의미합니다 (GNU
sed
에서 많은 편의를sed
).- 일반적으로
\n
및\t
와 같은 제어 문자 시퀀스는 지원되지 않습니다. - 레이블과 분기 명령 (예 :
b
) 뒤에는 별도의-e
옵션을 통해 실제 개행이나 연속이 있어야합니다 . - 자세한 내용은 아래를 참조하십시오.
- 일반적으로
그러나 두 버전 모두 POSIX 표준 확장 을 구현 합니다 .
- 그것들이 구현 하는 확장 기능은 다르다 (GNU
sed
는 더 많은 것을 구현한다). - 이들이 모두 구현 한 확장 도 부분적으로 구문이 다릅니다 .
두 플랫폼을 모두 지원해야하는 경우 (차이점 설명) :
호환되지 않는 기능 :
인수 없이
-i
옵션 을 사용 하면 (백업없이 현재 위치에서 업데이트 중) 호환되지 않습니다.- BSD
sed
: 반드시-i ''
사용해야한다. - GNU
sed
: 반드시-i
(동등한 :-i''
)를 사용해야합니다 --i ''
사용하면 작동하지 않습니다.
- BSD
-i
GNUsed
와 최근 버전의 BSDsed
(예 : FreeBSD 10)에서 입력 파일 당 줄 번호 를 현명하게 켭니다. 그러나 macOS에서는 10.12부터 사용 하지 않습니다 .
-i
가 없으면 모든 버전이 입력 파일에 누적 적으로 숫자 줄을 표시합니다.마지막 입력 행에 후행 줄 바꿈이 없고 인쇄됩니다.
- BSD
sed
: 입력 행이 하나로 끝나지 않더라도 항상 출력에 개행 문자 를 추가합니다 . - GNU
sed
: 후행 줄 바꿈 상태를 유지합니다 . 즉, 입력 줄이 하나만있는 경우에만 줄 바꿈을 추가합니다.
- BSD
공통 기능 :
-
sed
스크립트를 BSDsed
지원하는 것으로 제한하면, 일반적으로-E
와 함께 플랫폼 특정 확장 정규 표현식 기능을 사용하는 것을 제외하고는 GNUsed
에서도 작동합니다. 분명히, GNU 버전에만 해당하는 확장 기능도 사용할 수 없습니다. 다음 섹션을 참조하십시오.
-
BSD 버전의 엄격한 요구 사항에 따라 크로스 플랫폼 지원 (OS X / BSD, Linux)에 대한 지침 :
MacOS 와 Linux 는 BSD와 GNU 버전의 sed
를 가리키는 데 종종 사용되는데, 이는 각 플랫폼의 주식 버전이기 때문입니다. 그러나 brew install gnu-sed
와 함께 Homebrew 를 사용하여 macOS에 GNU sed
를 설치할 수 있습니다.
주 : -r
및 -E
플래그 ( 확장 정규 표현식)를 사용하는 경우를 제외하고는 아래 지침은 POSIX 호환 sed
스크립트 작성에 해당합니다.
POSIX를 준수하려면 유감스럽게도 이름에서 알 수 있듯이 매우 기본적인 POSIX BRE ( 기본 정규식)로 제한해야합니다.
주의 사항 :\|
,\+
및\?
지원됩니다 :--posix
가 사용되지 않는 한 GNUsed
가 지원하지만, BSDsed
는 지원하지 않습니다. 이러한 기능은 POSIX와 호환 되지 않습니다 .
\+
및\?
POSIX 호환 방식 으로 에뮬레이트 될 수 있습니다 .
\{1,\}
은\+
,
\{0,1\}
대한\?
,
\|
(교대) , 불행히도, 수 없습니다 .좀 더 강력한 정규 표현식을 사용하려면 ERE ( 확장 정규 표현식 )를 지원하기 위해
-E
(-r
대신 )를 사용하십시오 (GNUsed
는-E
문서화하지 않지만-r
의 별명으로 작동합니다), 새로운 버전의 BSDsed
, FreeBSD 10에서와 같이 이제는-r
을 지원하지만, 10.12에서의 macOS 버전은 그렇지 않습니다 .
주의 사항 :-r
/-E
사용하더라도 명령이 POSIX와 호환 되지 않는다고 하더라도 POSIX ERE (확장 정규 표현식)로 제한 해야합니다. 슬프게도, 이것은 당신이 여러 유용한 구조를 사용할 수 없다는 것을 의미합니다 :- 워드 경계 어설 션은 플랫폼에 따라 다르므로 (예 : Linux에서는
\<
, OS X에서는[[:<]]
). - (캡처-그룹의 대체 문자열에서 일치하는 "백 참조"반대로 정규 표현식 내부의 백 참조
s
BSD의 때문에, 함수 호출)sed
그렇게하지, 호기심, 확장 된 정규 표현식에 그들을 지원하지 않습니다 (하지만 기본적인 것들, 그들은 POSIX 위임 된 곳이다).
- 워드 경계 어설 션은 플랫폼에 따라 다르므로 (예 : Linux에서는
\n
및\t
와 같은 제어 문자 이스케이프 시퀀스 :regexes (라인 선택을위한 패턴과
s
함수의 첫 번째 인자 모두)에서,\n
만 이스케이프 시퀀스로 인식된다고 가정합니다 (거의 사용되지 않습니다. 패턴 공간은 일반적으로\n
을 종결하지 않고 단일 행이기 때문에). 예를 들어이, 있도록하지만, 문자 클래스 내부가 아니라[^\n]
.; 작동하지 않습니다 귀하의 의견이 더 제어 문자가없는 경우 이외 (\t
, 당신은 에뮬레이션 할 수 있습니다[^\n]
와[[:print:][:blank:]]
. 그렇지 않으면, 스플 라이스 제어 문자가 리터럴로 [2]) - 일반적으로 통해 중, 리터럴과 같은 제어 문자를 포함 접합 된 ANSI C-인용 문자열 (예를 들어,$'\t'
)에서 (bash,
ksh,zsh
)를 지원하거나printf
(예 :"$(printf '\t')"
)를 사용하여 명령 대체를 통해 수행 할 수 있습니다.- Linux 전용 :
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
- OSX 및 Linux :
sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
- Linux 전용 :
s
명령과 함께 사용되는 대체 문자열에서 제어 문자 이스케이프 시퀀스가 지원되지 않는다고 가정합니다. 다시 제어 문자를 포함합니다. 위와 같이 리터럴 로.- Linux 전용 :
sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
- macOS 및 Linux :
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Linux 전용 :
받는 텍스트 인수에 대한 동감
i
과 기능 : 제어 문자 시퀀스를 사용하지 않는 - 아래를 참조하십시오.a
라벨과 브랜칭 :
b
와t
함수에 대한 label-name 인수 뿐만 아니라 라벨 에는 리터럴 개행 문자 또는 스플 라이스 된$'\n'
이 와야합니다 . 또는 여러 개의-e
옵션을 사용하고 레이블 이름 뒤에 각 오른쪽 끝을 지정하십시오.- Linux 전용 :
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
- macOS 및 Linux :
- 둘 중 하나 (실제 줄 바꿈) :
sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
- OR (spliced-in
$\n
인스턴스) :
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
- OR (여러 개의
-e
옵션) :
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- 둘 중 하나 (실제 줄 바꿈) :
- Linux 전용 :
텍스트 삽입 / 추가를위한 함수
i
와a
: 텍스트 인수를 지정하기 전에 함수 이름 뒤에\
붙이고, 리터럴 개행 문자 나 스플라인 인$'\n'
따라야합니다 .- Linux 전용 :
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
- OSX 및 Linux :
sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
- 노트 :
-
-e
없으면 텍스트 인수는 macOS (bug?)의 출력에서 줄 바르게 종료되지 않습니다. - 텍스트 인수에서
\n
과\t
같은 제어 문자 이스케이프 는 Linux에서만 지원되므로 사용하지 마십시오 . - 따라서 텍스트 인수에 실제 내부 줄 바꿈 문자가 있으면
\
이스케이프합니다. - 텍스트 인수 다음에 추가 명령을 배치하려면 리터럴 또는 스플라인이 적용된 (이스케이프되지 않은) 개행 문자로 종료하거나 별도의
-e
옵션을 사용하여 종료해야합니다 (모든 버전에 적용되는 일반적인 요구 사항) .
-
- Linux 전용 :
기능 목록 내부 (여러 기능에 동봉 호출
{...}
, 또한 닫기 전에 마지막 기능을 종료해야합니다)}
와;
.- Linux 전용 :
-
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
-
- macOS 및 Linux :
-
sed -n '1 {p;q;}' <<<$'a\nb'
-
- Linux 전용 :
GNU sed
특정 기능 이 BSD sed
에서 빠져있다.
두 플랫폼을 모두 지원해야하는 경우에 놓칠 GNU 기능 :
다양한 정규식 일치 및 대체 옵션 (줄 선택과
s
함수의 첫 번째 인수에 대한 패턴 모두) :- 대소 문자를 구분하지 않는 정규식 일치를위한
I
옵션 (엄청나게, BSDsed
는 이것을 전혀 지원하지 않습니다). - 여러 줄 일치를위한
M
옵션 (^
/$
은 각 줄 의 시작 / 끝과 일치 함) -
s
기능과 관련된 추가 옵션은 https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command를 참조 하십시오.
- 대소 문자를 구분하지 않는 정규식 일치를위한
이스케이프 시퀀스
제한 범위 내에서 하위 문자열 조작 을 허용하는
s///
함수의 대체 인수에서\u
와 같은 대체 관련 이스케이프 시퀀스; 예 :sed 's/^./\u&/' <<<'dog' # -> 'Dog'
http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022를 참조하십시오 . -명령제어 문자 이스케이프 시퀀스 :
\n
,\t
, ..., 코드 포인트 기반 이스케이프; 예를 들어 다음 이스케이프 (16 진수, 8 진수, 10 진수)는 모두 작은 따옴표 ('
)를 나타냅니다 :\x27
,\o047
,\d039
- https://www.gnu.org/software/sed/manual/을 참조 하십시오. sed.html # 이스케이프
같은 주소 확장,
first~step
모든 단계 번째 라인에 맞게는addr, +N
다음 N 라인에 맞게addr
, ... - 참조 http://www.gnu.org/software/sed/manual/sed을. html # Addresses
[1] macOS sed
버전은 FreeBSD 및 PC-BSD와 같은 다른 BSD 계열 시스템의 버전보다 오래된 버전입니다. 불행히도 이것은 예를 들어 FreeBSD에서 작동하는 기능이 macOS에서 작동한다고 가정 할 수 없다는 것을 의미합니다.
[2] ANSI C 인용 문자열 $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'
은 \n
(및 NUL)을 제외한 모든 ASCII 제어 문자를 포함하므로 [:print:]
와 조합하여 사용할 수 있습니다 [:print:]
[^\n]
의 매우 견고한 에뮬레이션을 위해 :
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']
모든 개행을 탭으로 대체하십시오.
참고 : 간결함을 위해 명령은 here-strings ( <<<
) 및 ANSI C- 인용 문자열 ( $'...'
)을 사용 합니다. 이 두 쉘 기능은 bash
, ksh
및 zsh
에서 작동합니다.
# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3
# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'
# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'
BSD Sed 노트 :
실제 개행이나 별도의
-e
옵션을 사용:a
레이블 (:a
) 및 분기 명령 (ba
)을 종료해야 할 필요성에 유의하십시오.\t
와 같은 제어 문자 이스케이프 시퀀스는 대체 문자열에서 지원되지 않으므로 ANSI C 인용 탭 리터럴 이 대체 문자열로 연결됩니다.
( 정규 표현식 부분에서 BSD Sed는\n
을 이스케이프 시퀀스 로만 인식합니다.)
리터럴 텍스트를 함수 'a'가있는 행에 추가합니다.
참고 : 간결함을 위해 명령은 here-strings ( <<<
) 및 ANSI C- 인용 문자열 ( $'...'
)을 사용 합니다. 이 두 쉘 기능은 bash
, ksh
및 zsh
에서 작동합니다.
# GNU Sed
$ sed '1 a appended text' <<<'line 1'
line 1
appended text
# BSD Sed (multi-line form)
sed '1 a\
appended text' <<<'line 1'
# BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
sed $'1 a\\\nappended text' <<<'line 1'
BSD Seed가 추가 할 텍스트를 전달하기 위해 실제 줄 바꿈 뒤에 \
가 필요한 방법에 유의하십시오.
관련 i
(삽입) 및 c
(삭제 및 삽입) 기능에도 동일하게 적용됩니다.