Shell - sed 명령어

22 April 2016

지난번에 grep 정리한 것(http://soy.me/2016/03/24/grep) 이 꽤 도움이 되었기에, 이어서 sed도 정리해본다.

sed

  • 비 대화식 편집기. stream editor.
  • 원본 파일은 변경되지 않으며, 편집 결과는 표준 출력으로 출력된다.
  • 파일 내에서 편집을 할 범위와, 그 범위에 대해 적용할 명령을 지정하는 방식으로 편집한다.
  • 명령은 line by line으로 적용된다.

sed 명령어의 반환 값

  • grep은 패턴을 찾았으면 0, 찾지 못하였으면 1을 종료 상태로 반환한다.
  • sed는 검색 결과와는 무관하게 문법 오류가 발생하지 않았다면 0을 반환한다.

sed 정규표현식

  • sed 명령어에서 정규표현식을 나타낼 때는 /표현식/과 같이 슬래시로 감싼다.
  • 슬래시 외에도 다른 문자를 구분자로 사용할 수 있는데, 사용할 문자 앞에 역슬래시를 붙여주기만 하면 된다. \#정규식\#

정규표현식 메타문자

grep과 유사하게, sed 또한 패턴 검색을 위한 메타문자를 지원한다.

메타문자 기능
^ line의 맨 앞
$ line의 맨 뒤
. 아무 문자 1개
* 아무 문자 0개 이상
[abc] or [a-z] 괄호 안의 문자 집합 중 한 개와 일치
[^abc] or [^a-z] 괄호 안의 문자 집합에 없는 글자와 일치
\< 단어의 시작
\> 단어의 끝
\(문자\) 괄호 안의 문자를 capture. capture된 부분은 레지스터에 저장되어 \1, \2, \3..으로 참조할 수 있다.
a\{m\} 문자 a를 m번 반복
a\{m,\} 문자 a를 m번 이상 반복
a\{m,n\} 문자 a를 m번 이상 n번 이하 반복
& 패턴 매칭된 부분을 기억해서 치환문으로 사용한다. s/love/**&**/ 라고 하면 love > **love**가 된다.

sed 명령어의 사용법

숫자(줄 번호)와 정규표현식의 조합으로 편집하고자 하는 범위를 지정하고, 그 범위의 각 line에 대해 처리할 명령을 명시한다.

명령 d : delete

line number로 범위 지정하기

$ sed '^d' file		# 첫번째줄(^)을 삭제(d)
$ sed '$d' file		# 마지막줄($)을 삭제(d)
$ sed '3d' file		# 세번째줄을 삭제(d)
$ sed '1,3d' file	# 1~3 line을 삭제(d)
$ sed '1,3!d' file	# 1~3 line을 제외(!)한 모든 줄을 삭제(d)

정규표현식으로 범위 지정하기.

$ sed '/hello/d' file	# 정규식 /hello/에 매칭되는 모든 줄을 삭제

정규식 /hello/가 처음으로 매칭되는 줄 이후부터 끝($)까지 삭제.

$ sed '/hello/,$' file

정규식 /hello/가 처음으로 매칭되는 줄 이후부터, /bye/가 처음으로 매칭되는 줄 까지 삭제. 만약 bye가 한 번도 나오지 않는다면 파일의 끝($)을 범위로 한다.

$ sed '/hello/,/bye/' file

명령 p : print

$ sed '/[Hh]ello/p' file	# Hello, hello가 포함된 줄을 출력(p)

명령 s : substitution (치환)

$ echo "hi" | sed 's/hi/hello/' 	# hello
$ echo "hi hi" | sed 's/hi/hello/' 	# hello hi
$ echo "hi hi" | sed 's/hi/hello/g' 	# hello hello
$ echo "hello" | sed 's/hello/& world/g'	# hello world (`&`는 패턴 매칭된 부분을 의미)

명령 r : read file

$ sed '/hello/r datafile' file

hello가 나타나는 줄의 다음 줄에, datafile의 내용을 읽어서 삽입한다.

명령 w : write to file

$ sed '/hello/w newfile' file

hello가 나타나는 줄들을 newfile 이라는 파일명으로 저장한다.

명령 a : append

r 명령과 결과는 비슷한데, 삽입할 내용을 파일에서 읽는게 아니라, sed 다음줄에 직접 입력한다.

$ sed '/hello/a\
contents to append' file

이렇게 a 명령 뒤에 역슬래시 \를 붙여서 다음 줄로 넘어간 후, 삽입할 내용을 입력하고, closing ‘를 입력하고, 파일명을 입력한다.

$ sed '/hello/a contents to append' file	# error

이렇게 한 줄로 입력할 수 없다. 에러 난다.

삽입할 내용이 여러줄일때는, 맨 마지막 줄을 제외한 모든 줄의 끝에 역슬래시 ‘'를 붙여야한다.

$ sed '/hello/a\	# 여기 역슬래시
append1\		# 여기 역슬래시
append2' file		# 여기는 필요 없음

명령 i : insert

a 명령과 유사한데, 입력된 내용을 매칭된 줄의 다음 줄이 아니라 윗 줄에 삽입한다. a 명령과 마찬가지로 역슬래시를 붙여야한다.

$ sed '/hello/i\'
contents to insert' file

명령 c : change

a, i 명령과 유사한데, 입력된 내용을 매칭된 줄에 덮어쓴다. 즉 해당 줄 자체를 완전히 교체한다.

$ sed '/hello/c\'
contents to change' file

명령 n : 매칭된 줄의 다음 줄을 대상으로 명령을 적용

$ sed '/hello/{ n; s/world/World/g; }' file

hello가 나타나는 줄의 바로 다음줄을 대상으로 s/world/World/g; 명령을 적용한다. { }괄호는 여러개의 명령문을 묶기 위해 사용한다. 이 때 각 명령 뒤에는 반드시 세미콜론을 붙인다.

명령 y : 문자 변환 명령. 왼쪽 부분과 오른쪽 부분의 문자들이 1:1로 대응되어 변환된다.

$ sed '1,3y/abcd/ABCD' file

1~3 line에 대하여, a->A, b->B, c->C, d->D 로 변환한다. y 명령에서는 정규표현식 메타문자가 동작하지 않는다.

명령 q : 종료. 패턴 매칭이 되는 줄이 나타나면 sed 명령이 종료된다.

$ sed '5q' file		# 5번째 줄까지 출력하고 종료.

명령 h, g : hold, get

h 명령은 해당 줄을 별도의 hold buffer에 저장한다. g 명령은 hold buffer에 있는 내용을 현재 줄의 다음 줄에 추가한다.

$ sed -e '/hello/h' -e '$g' file

hello 나타나는 줄을 홀드 버퍼에 저장하고, 맨 마지막줄($)의 다음 줄에 홀드 버퍼의 내용을 추가한다. 즉 hello가 나타나는 줄을 복사하여 맨 마지막줄에 붙여넣은 것과 같은 효과를 낸다.

/hello/h 대신 /hello/{h; d;} 라고 하면, hello가 나타내는 줄을 잘라내기 하여 맨 마지막줄에 붙인 효과를 낸다.

명령 h, x : hold, exchange

앞서 본 것 처럼 h 명령은 해당 줄을 별도의 hold buffer에 저장한다. x 명령은 현재 줄의 내용을 hold buffer에 있는 내용으로 교체한다.

$ sed -e '/hello/h' -e '$x' file

원래 있던 맨 마지막 줄의 내용이 hello가 나타나는 줄의 내용으로 교체된다.

sed 명령어의 옵션

sed -n 옵션

기본 출력을 막는다.

$ sed -n '/[Hh]ello/p' file	# Hello, hello가 포함된 줄만 출력(p)

여기서 -n 옵션을 붙이지 않으면, 기본 출력으로 전체 파일의 내용이 출력되며 p 명령을 지정했기 때문에 패턴 매칭된 줄은 두 번씩 출력된다. 따라서 기본 출력을 막고 Hello, hello가 포함된 줄만 출력하기 위하여 -n 옵션과 p 명령어를 함께 사용한다.

sed -e 옵션

명령을 여러개 사용할 때 사용한다.

sed -e 's/hello/Hello/g' -e 's/world/World/g' file
node.js heapdump 생성하기 GMT와 UTC 차이, summer time