[데이터 추출 및 가공 05] sed 사용법 3 : 정규 표현 (regular expression) (1) + 기호 사용, 그리고 csv형식 변환

Home / 데이터 추출과 가공 / [데이터 추출 및 가공 05] sed 사용법 3 : 정규 표현 (regular expression) (1) + 기호 사용, 그리고 csv형식 변환

sed 사용법 3 : 정규 표현 (regular expression) (1) + 기호 사용, 그리고 csv형식 변환

sed를 쓸 때 -r 옵션을 사용하면 좀더 흥미진진하게 텍스트를 가공할 수 있습니다. 정규표현(regular expression)을 이용할 수 있기 때문입니다. (Mac을 사용하는 사람은 -r옵션 대신 -E 를 써야합니다.)

정규표현은 텍스트 패턴을 표현하는데 사용합니다. 예를 들어 이메일 주소를 만들때는 일정한 규칙을 따라야합니다. @기호가 도메인과 유저네임 사이에 있어야 하고, 도메인과 유저네임도 아무렇게나 만들지 않고 일정한 규칙을 따라야합니다. 이렇게 규칙이 있는 텍스트의 패턴을 표현하는 것이 정규표현(regular expression)입니다.

sed 커맨드에서 정규표현을 사용하면 규칙이 있는 텍스트 패턴을 쉽게 찾을 수 있습니다. 이 때문에 정규표현을 사용할 수 있다는 것은 텍스트에서 데이터를 추출하거나 가공할때 아주 강력한 무기를 가지게 되는 것이나 마찬가지입니다. 대신 알아야 할 규칙들이 있습니다. 그래도 규칙을 배우는데 시간을 쓰는 것이 결코 아깝지 않을 만큼 유용합니다.

아주 쉬운 정규표현부터 시작하겠습니다. 터미널에서 아래의 커맨드를 실행해 보죠.

echo "abc aabc aaabc aaaabc" | sed -r 's/a+/A/g'

원래 echo는 다음에 오는 값들을 화면에 출력하지만,  |를 쓰면 화면에 출력하는 대신, | 다음에 쓴 커맨드에 마치 키보드로 입력하는 것처럼  넘긴다는 것을 지난번 글에서 설명했었습니다. 위의 경우에는 sed 커맨드에 키보드로  abc aabc aaabc aaaabc를 입력하는 것과 같습니다. 위의 전체 커맨드의 결과는 다음과 같습니다.

Abc Abc Abc Abc

a aa aaa aaaa 각각을 모두 A로 바꿨습니다. a+는 a가 하나 또는 여러개가 연달아 있는 텍스트 패턴을 표현합니다. 따라서 위의 sed 커맨드는 이런 텍스트 패턴을 찾아내어 A로 바꾸는 겁니다. 만약에 키보드의 문제로 a를 치면 a가 여러번 찍히는 경우에, 중복된 a를 하나의 a로 바꾸는데 사용할 수도 있습니다. 그럴땐 위의 커맨드에서 A를 a로 바꿔주면 됩니다.

echo "abc aabc aaabc aaaabc" | sed -r 's/a+/a/g'

결과는 다음과 같습니다.

abc abc abc abc

b가 하나 또는 여러개가 연달아 있는 것을 하나의 b로 바꾸려면 ‘s/b+/b/g’를 쓰면 되고,  c가 하나 또는 여러개가 연달아 있는 것을 하나의 c로 바꾸려면 ‘s/c+/c/g’를 쓰면 됩니다.

중복된 공백을 하나의 공백으로 바꿀려면 ‘s/ +/ /g’를 써서 다음과 같이 사용하면 됩니다.

echo "a b  c   d    e      f       g        h         i" | sed -r 's/ +/ /g'

결과는 다음과 같습니다.

a b c d e f g h i

중복된 공백을 하나의 공백으로 바꿉니다.

때로는 줄 맨 앞에 있는 공백을 다 없애고 싶을 때도 있습니다. 이런 경우에는 아래와 같이 줄 맨앞을 의미하는 ^기호를 앞에 먼저 쓰고 공백을 입력한 다음 +기호를 덧붙힙니다. 그런 다음에 오는 //사이에 아무것도 쓰지 않으면 됩니다.

echo "    abcd efgh" | sed -r 's/^ +//'

줄 맨 앞의 공백을 찾아 아무것도 없는 글자로 바꿉니다. 다시 말해 지워버린다는 얘기입니다. 여기에서 s/^ +// 뒤에 g를 붙일 필요가 없습니다. 줄 맨앞에 있는 공백은 한번만 바꿔주면 충분하기 때문입니다. 하지만 g를 맨뒤에 붙여도 결과는 마찬가지입니다.

줄 맨 뒤에 있는 공백을 다 없애고 싶을 때도 있습니다. 이런 경우에는 줄 맨끝을 의미하는 $기호를 뒤에 붙이면 됩니다.

echo "abcd efgh    " | sed -r 's/ +$//'

줄 맨뒤의 공백을 찾아 다 지웁니다. 여기에서도 마찬가지로 바꾸는 작업을 한번만 하기 때문,  s/ +$//뒤에 g를 붙일 필요가 없습니다. 결과는 잘 보이지 않지만 나중에 파일안에 있는 이런 공백을 없애면 그만큼 파일 크기가 줄어듭니다.

이제 앞뒤에 있는 공백을 없애려면 어떻게 할까요?
몇가지 방법이 있지만 가장 간단한 방법은 sed를 두번 쓰는 겁니다. sed를 한번 쓴 다음에 결과를 파이프(|)로 두번째 sed로 넘겨주면 되겠습니다.

echo "    abcd efgh    " | sed -r 's/^ +//' | sed -r 's/ +$//'

첫번째 sed 커맨드를 거치면서 줄 앞의 공백이 지워지고, 두번째 sed를 거치면서 줄 뒤의 공백이 지워집니다.

sed의 옵션인 -e를 쓰면 한번의 sed로도 처리할 수 있습니다. 아래와 같이 각각의 ‘s/…/…/’앞에 -e를 붙이면 됩니다.

echo "    abcd efgh    " | sed -r -e 's/^ +//' -e 's/ +$//'

이번에는 텍스트의 모든 줄에서 줄 맨앞의 공백과 줄 맨 뒤의 공백을 모두 지우고, 중간에 연달아 있는 공백을 하나의 공백으로 바꿔보겠습니다. 일단 data1.txt라는 텍스트 파일을 하나 만들고 시작하겠습니다. 아래의 커맨드를 치면 키보드로 텍스트를 한줄 한즐 칠때 마다 그내용을 data1.txt에 저장합니다.

cat > data1.txt

원하는 내용을 다 키보드로 입력한 다음 맨 마지막에 Ctrl+d를 치면 입력이 끝나고, 그전에 입력한 모든 내용이 data1.txt에 저장됩니다. 다음과 같은 내용을 입력해 data1.txt에 저장해보겠습니다. 모든 줄의 맨 앞부분에 4개의 공백이 있습니다. 줄 뒷부분에도 원하는 만큼 공백을 키보드로 치면 되겠습니다. 키보드 입력을 마칠려면  맨 마지막 줄을 입력하고 Ctrl+d를 치면 됩니다.

cat > data1.txt
    id   date        sales
    100  02/01/2017  $120.00
    101  03/03/2017  $230.00
    102  03/29/2017  $50.00

data1.txt에 어떤 내용이 들어가 있는지는 cat data1.txt를 쳐서 확인할 수 있습니다.

cat data1.txt
    id   date        sales
    100  02/01/2017  $120.00
    101  03/03/2017  $230.00
    102  03/29/2017  $50.00

키보드로 입력한 내용이 잘 들어가 있습니다.

이제 각각의 줄의 맨 앞부분 공백과 맨 뒷부분 공백을 모두 지우고, 중간에 연달아 있는 공백을 공백 하나로 바꿔 보겠습니다. cat data1.txt가 화면에 출력하는 파일 내용을 sed 커맨드의 키보드 입력처럼 넘길려면 | 기호를 중간에 넣으면 된다고 했습니다. 이를 이용해 보겠습니다.

cat data1.txt | sed -r -e 's/^ +//' -e 's/ +$//' -e 's/ +/ /g'
id date sales
100 02/01/2017 $120.00
101 03/03/2017 $230.00
102 03/29/2017 $50.00

sed 커맨드에서 ‘s/^ +//’는 줄 맨앞의 공백을 모두 지우고, ‘s/ +$//’는 줄 맨끝의 공백을 모두 지웁니다. 그런 다음  마지막 ‘s/ +/ /g’는 중간에 중복된 공백을 하나의 공백으로 바꿉니다.

위에서 화면에 출력하는 결과를 data2.txt파일에 저장하려면, 화면에 출력하는 내용을 파일에 저장하는 기호인 >를 써서 다음과 같은 커맨드를 실행하면 됩니다.

cat data1.txt | sed -r -e 's/^ +//' -e 's/ +$//' -e 's/ +/ /g' > data2.txt

마이크로소프트 엑셀이 읽을 수 있는 파일형식의 하나로 csv 형식이 있습니다. csv는 comma-separated values의 준말로 각각의 값을 쉼표로 구분한 형식입니다. 위의 데이터로 csv 형식으로 만들면 다음과 같습니다.

id,date,sales
100,02/01/2017,$120.00
101,03/03/2017,$230.00
102,03/29/2017,$50.00

그럼 data1.txt을 위와 같은 형식으로 바꿔 data1.csv에 저장하려면 어떻게 할까요? 중복된 공백을 하나의 공백으로 바꾸는 ‘s/ +/ /g’를 쓰는 대신, 중복된 공백을 쉼표로 바꾸는 ‘s/ +/,/g’로 쓰면 됩니다.

cat data1.txt | sed -r -e 's/^ +//' -e 's/ +$//' -e 's/ +/,/g' > data1.csv

cat커맨드를 써서 data1.csv에 저장된 내용을 확인하면 다음과 같습니다.

cat data1.csv
id,date,sales
100,02/01/2017,$120.00
101,03/03/2017,$230.00
102,03/29/2017,$50.00

이제 data1.csv는 엑셀로 읽을 수 있습니다. 하지만 앞으로 엑셀을 쓰지 않고 커맨드나 프로그래밍으로 데이터를 처리할 예정입니다. 그래도 csv형식으로 파일을 저장하는 것이 때로는 유용하게 쓰일때가 있습니다. 다른 사람이 데이터를 처리할때 쉽게 다룰 수 있도록 배려하는 차원도 있고요.