좋은 지침서로는 O’Reilly handbook for sed and awk 이랍니다. 책 제목인지, 책 설명인지는 모르겠지만(한번도 본적이 없어서) 이정도면 원서를 다루는 서점에서는 찾을 수 있겠지요. (영어입니다. 껄껄) “UNIX in a Nutshell” , “UNIX Power Tools” 같은 책도 추천한다네요. (게을러서인지, 아직 한글 관련 문서를 발견하지를 못했습니다. 아시는 분 있으면 소개좀. 책 말고요 – 돈이 없어서 )
sed: 무엇에 쓰는 물건인고?
이글 제일 앞에서 설명한 바로 그런 작업을 보다 쉽게 해주는 물건이랍니다.대부분의 유닉스 명령어가 그렇듯이 이것도 단지 표준 입력으로 입력받아,원하는 처리를 해서, 표준 출력으로 그 결과를 보는 일 밖에 하지 않습니다.
최종목표는 현재 디렉토리와 그 하위 모든 디렉토리에 있는 .html 파일 안에 있는 모든 “Index”라는 문자열을 “색인”이라는 문자열로 바꾸는 것이지만, sed가 하는 일은 딱 하나, 무조건 표준 입력에서 입력되는 내용 중에, “Index”라는 문자열이 있으면, 그것을 “색인”이라는 문자열로 바꾸어서 표준 출력으로 보내는 일 밖에 하지 않습니다.
결국 나머지 일들은 쉘 스크립트에서 또 다른 명령어나, 쉘 스크립트 언어를 사용해야겠지요.
그 사용법은
sed ‘s/찾는문자열/바꿀문자열/g’ 입력파일
이것이 가장 기본적인 사용법이랍니다. 이렇게 하면 앞에서 말했듯이 그 결과는 표준 출력으로 보내집니다. 또한 문자열을 지정할 때, 쉘 스크립트 작성때와 마찬가지로, 쉘에서 특별한 의미로 쓰이는 문자들은 ” 문자를 앞세워서 사용합니다.
.*[]^$
이 문자들이 sed, shell에서 특별한 의미로 쓰임으로 이 문자 자체를 의미하려면, ” 문자를 먼저 사용해야겠지요.
예:
sed ‘s/[J.S. Bach {$ for music}]/[Bach, J.S {$ for music}]/’ filename
이게 아니라,
sed ‘s/[J.S. Bach {$ for music}]/[Bach, J.S {$ for music}]/’ filename
이렇게.
여기서 하나 신기한 것은 “찾는 문자열”에서만 이런 것이 적용된다는 것입니다. “바꿀 문자열”에서도 똑같이 지정하면, 그 지정한 그대로 출력되더군요. (신기하나? 원래 당연한 것 아닌감? 표준 출력이니까.)
그럼 이것은 무엇일까요?
sed ‘s//usr/bin//bin/g’ filename
“/usr/bin” -> “/bin” 으로 바꾸는 것? 물론 오류가 있는 사용법은 아닙니다. 하지만, 경로명이 길어지면, 알아 보기가 힘들겠지요. 그래서, 경로명을 사용할 때는
sed ‘s#/usr/bin#/bin#g’ filename
이렇게 한답니다.
또한 “Index”라는 문자열은 “색인”으로 바꾸고, “Contents”라는 문자열은 “차례”라는 내용으로 바꾸고 싶다면, sed를 두번 사용하느냐? 이런 멍청한 짓(?) 하는 사람은 없겠지요. 이럴 때는
sed -e ‘s/Index/색인/g’ -e ‘s/Contents/차례/g’ 파일이름
이런 식으로 한답니다. ‘-e’ 옵션은 “또 있다”는 뜻이랍니다. 이 옵션이 빠지면, 첫번째 경우만 처리하고 두번째 경우(“차례”로 바꾸는 것)는 무시된다고 하네요.
정규표현식(Regular Expression) 사용하기
모든 찾기가 그러하듯이 여기서도 여전히 정규식이 사용되는군요.정규식 사용하는데 무리가 없는 사람은 별로 어려운 문제가 아니겠지요. 저는 잘 모르니까, 몇가지 예제를 들어보지요.
sed ‘s/^Thu /Thursday/’ filename
이건 저도 아네요. 껄껄. ‘^’ 기호는 그줄의 첫칸을 의미하지요. 즉, 줄 첫 칸에만 있는 “Thu” 문자열을 “Thursday”로 바꾸는 경우네요. 그런데, 여기서는 파일 전체를 대상으로 한다는 ‘g’ 문자가 빠졌군요. 왜 빠져도 되는지는 모르겠지만, 아무튼 실행되더군요.
sed ‘s/ $//’ filename
이건 반대로 줄 끝에 있는 공백 문자를 없애는 것입니다. 즉 ” $” 문자열을 “” 문자열로. 텍스트 파일에 대한 기본적인 지신이 부족한 사람들에게는 “그게 뭐 어때서?” 하면서 의아해 하겠지만, 엄격히 따지면, ” $” 문자열이란, 공백문자랑, 그 다음에 줄 바꿈 문자가 있는 것을 말합니다. 이것을 윗 명령으로 그 공백 문자를 없애는 경우입니다.
과연 이런 게 어디 쓰일까? 회의를 둘 수도 있겠지만, 의외로 필요할 때가 많습니다. 한 예를 들어 awk (요곤 기회 주어지면 다음에 하지요. sed 보다 복잡하더군요.) 에서 마지막 필드 다음에 줄바꿈 문자가 있어야 되는데, 이렇지 못하고, 공백문자가 있어, 원하는 결과 값을 못 얻어 내는 경우가 있거든요. 이럴 때 유용하게 쓰입니다.
sed ‘s/^$/이건 빈 줄이다/’ filename
줄 첫칸에 줄 바꿈 문자가 있다? 당연히 빈줄이지요. 껄껄.
sed ‘s/Apr .. ..:..:.. 1980/Apr 1980/g’ filename
이런 식으로 많이 사용하지 않았나요? vi 편집기나, grep 명령에서 말입니다. ‘.'(점)은 임의한 한 문자를 뜻하지요. 윗 예제는 뭔고하면, “Apr 11 11:09:25 1980” 이런 식으로 (어디서 많이 보았지요?) 된 여러 경우들을 무조건 “Apr 1980″으로 통일하는 경우입니다.
sed ‘s/[Oo]pen[Ww]in/openwin/g’ filename
sed ‘s/ [A-Z]. / /g’ filename
이것도 그럴 것 같은데. ” D. ” 문자열 같은게, ” ” 문자열로 바꾸는 것입니다.
sed ‘s/ [^A-DHM-Z]. / /g’ filename
이건 윗 예제와 반대지요. 즉, A,B,C,D,H,M,O,P,Q,R,S,T,U,V,W,Z,Y,Z 문자는 제외한 다른 단일 문자의 경우는 모두 공백문자로. 그 외에도 몇개 더 있는데, 뭐 그다지 중요한 것은 아니네요. grep나, ls 명령에서 이미 잘 쓰고 있는 것들이니까,
* : 임의의 문자열.
[][^] 등.. 여러 표현식을 섞어서 사용하는 것.
sed 안에서도 자체적으로 저장을 한다는군요. (신기하기도해라) 이 말이 무신 말인고 하면, 앞에서 말한 sed의 개념으로 본다면, 단지, 표준 입력으로 입력받아, 표준 출력으로 단순히 변환해서 보내는 역활밖에 하지 않는데, 저장할 여력이 어디 있을까 하는데…..
이런 경우를 생각해 보지요.
“*남자*와 *여자*”라는 정규식에 맞는 문자열에서 공백문자를 두고 서로 바꾸어야할 경우. 지금까지의 개념으로 본다면, 이런 문제는 sed에서 불가능하지요. 먼저 발견되는 첫번째 환경을 저장하고, 다음 두번째 환경이 곧이어 발견되면 그것을 서로 바꾸면 되겠지요.
이렇게 하는 것이 “(” “)” (괄호)입니다.
sed ‘s/^([A-Z][A-Za-z]*), ([A-Z][A-Za-z]*)/2 1/’ filename
이것은 “문자열1, 문자열2” 이런 내용을 “문자열2 문자열1″로 바꾸는 것입니다. 어떻게 1, 2를 서로 바꾸느냐 하면, “바꿀문자열 지정부분에, 2 1 이런식으로 써주면 되지요.
영어 표현 중에, “Lastname, Firstname” 이런 것을 “Firstname Lastname” 이런 식으로 바꾸고자 할 때 유용하게 쓰인답니다. 필요에 따라 입력 파일의 특정 범위 내에서만 문자열 바꾸기를 해야할 경우가 생기는데, 이때는 s 앞에다 그 범위를 지정합니다.
sed ‘1,20s/foobar/fubar/g’ filename
이것은 첫번째 줄부터 20번째 줄까지만 찾아서 바꾸는 것입니다.
sed ‘/^Aug/s/Mon /Monday /g’ filename
이런 식도 가능하다네요. 즉, 줄 처음에 Aug (팔월인가?) 라는 문자열이 있는 그 줄의 Mon 이라는 문자열을 Monday 로 바꾸는 것입니다.
이 반대라면,
sed ‘/^Aug/!s/Mon /Monday /g’ filename
이런 식으로. 또한 조건을 여러게 줄 수도 있습니다.
sed ‘/^Aug/,/^Oct/s/Mon /Monday /g’ filename
어떻게 작동할 지 알겠지요?
지금까지 설명 예로든 것은 모두 바뀌는 부분을 포함해서, 입력된 모든 내용을 다시 표준 출력으로 보여줍니다. 필요에 따라 그 바뀌는 줄에 대해서만 출력해야 할 경우가 생기지요.
sed -n ‘s/fubar/foobar/gp’ filename
이런 식으로 사용하는데, 이때 주의 할 것은 -n 옵션을 사용한다는 것과 끝부분에 g가 아니라, gp라는 것.
파일로 저장된 sed 명령. sed 스크립트.
여러 sed 명령을 계속 사용해야 할 경우는 이 작업을 또 보다 편하게 할 수 없을까? 해서, 생겨난 것이 스크립트인데, 가령,
s/color/colour/g
s/flavor/flavour/g
s/theater/theatre/g
한 파일에 이렇게 입력하고, sample.sed 라는 이름으로 저장한 후, 이것을 사용하려면 다음과 같이 합니다.
sed -f sample.sed filename
그럼 쉘 스크립트에서 실행 프로그램을 지정하는 #! 기호를 사용하면,
#!/usr/bin/sed -f
# This file is named “sample2.sed”
s/color/colour/g
s/flavor/flavour/g
s/theater/theatre/g
이렇게 작성하고, sample2.sed 라는 이름으로 저장한 후,
chmod u+x sample2.sed
./sample2.sed filename
이렇게 바로 하나의 독자적인 스크립트로 사용할 수도 있겠지요. 이상이 sed 맛보기 내용의 전부입니다. 얼마나 도움이 되었을지 의문이네요. sed 단독으로는 그리 유용하게 사용되지 못합니다. 이것을 제대로 사용하려면, 결국 유닉스에서의 텍스트 처리 명령들에 대해서 모두 꾀뚤고(?) 있어야 하겠더군요. 아무튼 저는 오늘 sed로 원하는 작업을 할 수 있었습니다.
다음에 시간나면, awk 맛보기를 올려보지요. 또 시간나면, flex도, 그리고, 기타 textutil 팻키지의 명령들도…아직까지는 아무래도 유닉스 쪽에서는 텍스트 처리 기능이 유용하게 쓰이나봅니다.