리눅스 명령어 정리(5) - sed

Ubuntu 14.04 LTS 환경을 기준으로 작성되었습니다.

sed

스트림 에디터라 부르며 지정한 지시에 따라 파일이나 파이프라인 입력을 편집해서 출력해주는 명령어

옵션
  • -e: 하나의 지시(여러 번 지정 가능)
  • -r: 확장 정규 표현식 사용(단, GNU 환경에서만 사용가능하고, OS X나 BSD 환경에서는 -E를 사용)
예시
$ echo "ccc" | sed -e "1i aaa" -e "1i bbb"
aaa  
bbb  
ccc  
$ cat test.txt | sed -e "4d" -e "6i abc" -e "s/dog/cat/" > result.txt

: test.txt에서 "dog"를 "cat"로 치환 => 6번째 줄에 "abc"를 삽입 => 4번째 줄을 제거한 결과를 result.txt 파일에 출력

$ cat test.txt | sed -e "s/abc/def/gi" > result.txt

: test.txt에서 "abc"를 "def"로 치환(g: 한 줄 안에서 해당하는 모든 부분 치환, i: 대소문자 차이 무시)한 결과를 result.txt 파일에 출력

원본 파일에 출력하기

위에서 주목해야할 점은 기존의 원본 파일 test.txt이 아닌 result.txt 파일에 출력한다는 점이다. 만약 result.txt 이 아닌 test.txt 파일로 리다이렉트를 해보면 test.txt 의 내용이 모두 사라지는 비극을 경험하게 될 것이다.
이는 sed 명령어 만의 문제가 아니라 하나의 명령어열에서 파일을 여는 조작과 기록하는 조작을 동시에 하였기 때문에 발생한 문제로, 그 결과 해당 파일의 내용이 모두 사라지는 경우가 생긴다.

만약 기존의 파일에 덮어쓰고 싶다면 별도의 스크립트를 작성하여 해결할 수 있다.

#!/bin/bash

source=$1  
tempfile="tempfile"  
mv $source $tempfile  
cat $tempfile | sed -e "4d" -e "6i abc" -e "s/dog/cat/" > $source  
rm $tempfile  
$ sh sed.sh test.txt
정규 표현식 이용하기

정규 표현식을 이용하여 치환할 수도 있다. 하지만 이 때 리눅스 환경에 따라 옵션 이름이 다름에 주의하자.

#!/bin/bash

case "$(uname)" in  
  Darwin|*BSD) sed="sed -E" ;; # OS X 또는 BSD 환경
  *) sed="sed -r" ;; # GNU 환경
esac

expr="s/(dog|cat|lion)/tiger/"

source=$1  
tempfile="tempfile"  
mv $source $tempfile  
cat $tempfile | $sed -e "$expr" > $source  
rm $tempfile  
sh expr.sh test.txt  

: test.txt 에서 "dog", "cat" 또는 "lion" 을 "tiger"로 치환

역참조

정규 표현식으로 찾은 문자열을 부분적으로 재사용하는 방법이다. 치환 전 문자열의 일부분이 치환 후에 다시 필요한 경우 이용한다.

applicant.csv 의 내용이 아래와 같다고 가정하자.

번호,이름,성별,생년월일,합격여부
1,Peter,남,930503,불합격  
2,John,남,911110,불합격  
3,Tom,남,880818,불합격  
4,Julia,여,89201,불합격  
5,Steve,남,921207,합격  
6,Alice,여,940616,불합격  

여기서 불합격자 중 90년대생 전체를 합격시키는 스크립트를 작성할려고 한다.
우선 정규표현식을 이용하여 생년월일이 "9"로 시작하는 패턴을 찾아야 한다. 하지만 여기서 치환해주어야 할 문자열은 정규표현식으로 찾아낸 생년월일이 아니라 그 뒤에 나오는 합격여부이다.

이 때 역참조를 이용하면 쉽게 해결할 수 있다. \1 이 앞에 내온 생년월일 부분을 대체하고 있다.

#!/bin/bash

case "$(uname)" in  
  Darwin|*BSD) sed="sed -E" ;; # OS X 또는 BSD 환경
  *) sed="sed -r" ;; # GNU 환경
esac

expr="s/(9[0-9]{5},)불합격/\1합격/"

source=$1  
tempfile="tempfile"  
mv $source $tempfile  
cat $tempfile | $sed -e "$expr" > $source  
rm $tempfile  
$ sh back_reference.sh applicant.csv
$ cat applicant.csv
번호,이름,성별,생년월일,합격여부
1,Peter,남,930503,합격  
2,John,남,911110,합격  
3,Tom,남,880818,불합격  
4,Julia,여,89201,불합격  
5,Steve,남,921207,합격  
6,Alice,여,940616,합격  

출처