sed 사용법 6
정규 표현 (RegEx) (4) : ^기호가 대괄호 []안에 들어갔을 때
^기호는 줄이 시작되는 것을 표현하는 기호임을 알아 보았었습니다. $기호도 있었는데 이 기호는 줄 맨끝을 표현하는 기호라는 것도 알아 보았었습니다.
그런데 ^기호가 대괄호([])안에 있을때는 다른 의미를 지닙니다. 예를 들어, [^a]는 a가 아닌 어떤 글자도 상관없다는 것을 표현합니다. 다음 커맨드를 보죠.
echo "His name is Kylian Mbappé." | sed -r 's/[^a]/X/g'
a가 아닌 모든 글자를 (공백도 포함해서) 모두 X로 바꿨씁니다. 혹시 모르니까 a뿐만 아니라 공백도 제외해보겠습니다. 그럴려면 ‘^a’다음에 ‘^ ‘를 추가해 [^a^ ]라고 쓰면됩니다. 커맨드 실행 결과를 보죠.
echo "His name is Kylian Mbappé." | sed -r 's/[^a^ ]/X/g'
공백은 그대로 두고 a를 뺸 다른 글자를 모두 X로 바꿨습니다. ^기흐를 []안에 쓰는 방법은 많은 글자리스트를 대괄호 [] 안에 다 쓰지 않고 특정 글자만 제외할 수 있어, 정규표현(RegEx)애서 아주 유용하게 쓸 수 있습니다.
한 가지 예를 들어 보겠습니다. 웹페이지의 소스는 HTML 형식으로 만듭니다. HTML형식의 보여주려는 내용을 상황에 따라 html tag로 묶습니다. 웹브라우저는 html tag를 통해 컴퓨터 화면에 웹페이지 내용을 어떻게 출력할지를 알아내고 그에 맞춰 출력합니다.
html tag는 영어로 angle bracket 한국어로 해석하먄 각괄호인 <>안에 필요한 정보를 담고 있습니다. 일부의 경우를 제외하면 html 태그 자체는 웹페이지의 주요 정보를 담고 있지 않습니다. 이러한 이유로 내려받은 html 파일에서 웹페이지 내용만 보려고 할떄 html tag를 제거할 필요가 종종 있습니다.
이번 기회에 html tag를 정규표현을 이용한 sed로 제거하는 방법을 알아보겠습니다. 그전에 먼저 curl 커맨드를 써서 html 소스를 내려받아 보겠습니다. 내려받은 html 소스는 pytorch_tutorials.html에 저장하겠습니다.
curl -s "https://pytorch.org/tutorials/" > pytorch_tutorials.html
딥러닝 코딩을 할때 사용하는 라이브러리의 하나인 PyTorch의 웹사이트에서 pytorch 강좌를 모아놓은 웹사이트입니다. 위의 코드로 내려받은 html 소스를 보려면, cat pytorch_tutorials.html 커맨드를 실행하면 되겠습니다. html tag가 뒤섞여 있어서 내용을 읽기가 쉽지 않습니다.
cat pytorch_tutorials.html
html tag를 제거해서 좀 더 내용을 알아볼 수 있게 만들어 보겠습니다. html tag는 <>로 둘러쌓여 있습니다. <>와 그사이에 있는 텍스트를 없애면 됩니다. 이를 잡아내는 정규표현을 만드는 방법은 다음과 같습니다.
1. <를 먼저 찾습니다.
2. 이어서 나오는 글자를 >가 나올때까지 다 잡아냅니다.
2. 그리고 마지막에 >을 잡아냅니다.
첫번째는 그냥 <를 쓰면 됩니다.
두번째는 >를 제외한 텍스트를 길이와 관계없이 찾으면 됩니다. 따라서 > 기호를 제외한 모든 글자를 의미하는 [^>]에 +를 붙여서 [^>]+라고 쓰면 됩니다. [^>]{1,}라고 써도 되겠습니다.
세번째는 그냥 >라고 쓰면됩니다.
셋을 전부 연결하면 <[^>]+> 가 됩니다. 이 정규표현은 <…>형태의 모든 텍스트를 표현합니다. 이를 이용해 html tag를 없애는 sed 커맨드f를 만들면 sed -r ‘s/<[^>]+>//g’ 가 됩니다.
이 커맨드에 이미 내려받은 html소스를 입력으로 넘기는 코드는 아래와 같습니다.
cat pytorch_tutorials.html | sed -r 's/<[^>]+>//g'
html tag는 다 지워졌는데 아무 것도 없는 줄이 많음을 확인할 수 있습니다. 아무것도 없는 줄을 지우는 작업도 해야 겠습니다. 혹시 아무것도 없어보이는 줄에 공백이 있을 수 있으니 공백만 있는 줄의 공백을 모두 지우는 것부터 하겠습니다.
그럴려면 ‘s/^ +\$//’ 을 추가해야 합니다. 줄 맨앞(^)과 맨뒤(\$)사이에 있는 공백만 있는 것을 정규표현으로 쓰면 ^ +\$ 입니다. 이런 줄을 찾아서 아무것도 없는 걸로 바꾸면 다시 말해 ‘s/^ +$//’ 작업을 하면 공백이 다 지워집니다. 따로 sed 커맨드를 쓸 필요없이 -e 옵션을 써서 이전 sed 커맨드에 추가하면 됩니다.
이렇게 해서 얻은 결과를 파이프(|)로 새로운 sed커맨드에 넘깁니다. 새 sed 커맨드에서는 -n 옵션을 써서 아무 글자도 없는 없는 줄은 출력하지 않게 해보겠습니다. 다시 말하면 뭐라도 글자가 있는 줄만 출력하게 하는 겁니다. 어떤 글자라도 있는 것을 표현하는 정규표현은 .+입니다. 이를 소괄호로 묶어 (.+)로 쓴 다음 똑같은 텍스트로 바꾸는 것은 s/(.+)/\1/ 로 합니다. 여기에 sed 의 -n 옵션과 결합해서 사용하면, 아무 글자도 없는 줄은 출력하지 않고 뭔가라도 글자가 있는 줄은 출력을 해서 아무것도 없는 줄은 사라집니다.
cat pytorch_tutorials.html | sed -r -e 's/<[^>]+>//g' -e 's/^ +$//' | sed -r -n 's/(.+)/\1/p'
‘s/(.+)/\1/p’ 대신 ‘/.+/p’를 써도 똑같은 작업을 합니다. 글자가 있는 줄만 프린트한다는 표현입니다.
cat pytorch_tutorials.html | sed -r -e 's/<[^>]+>//g' -e 's/^ +$//' | sed -r -n '/.+/p'
자바 스크립트를 포함하고 있지만 html tag는 하나만 남기고 모두 지워졌고 아무것도 없는 줄은 지워서 테스트만 남았습니다. 이제는 내용을 비교적 알아볼만 합니다.
이제는 이 웹페이지에 있는 링크를 모두 모아보겠습니다.
링크는 <a href=”…”>의 tag안에서 href다음에 있는 따옴표안에 있습니다. 이 따옴표 안에 있는 링크를 잡아내야 합니다.
따옴표안에 있는 텍스트를 잡아내 저장하는 정규표현은 “([^”]+)”입니다. 따옴표가 나오면 다음 따옴표가 나올때가지 모든 텍스트를 잡아냅니다. 따옴표안에 있는 텍스트를 다 잡아내는 것이 아니라, 따옴표 앞에 href= 가 붙어 있는 경우를 잡아내므로 정규표현은 href=”\([^”]+)” 가 됩니다.
다른 html tag 말고 <a…> 안에 들어있는 href=”…”에 관심이 있습니다. 따라서 <a href=”…”>의 따옴표안에 있는 잡아내야합니다. 이에 해당하는 정규표현은 앞에 <a 와 뒤에 >를 붙여 <a href=”\([^”]+)”> 가 됩니다.
종종 a와 href사이에 html tag 속성이 정보가 들어있을 수 있습니다. 이 때문에 a와 href 사이에 .\*를 추가할 필요가 있습니다. 그러면 정규표현은 <a .*href=”\([^”]+)”> 가 됩나다.
여기에 더해 아무 텍스트나 잡아내는 .+를 앞뒤에 붙여 .+<a .*href=”\([^”]+)”>.+ 라고 쓰면 필요한 정규표현이 완성됩니다.
이 정규표현으로 찾아낸 텍스트에서 소괄호로 묶여있어서 저장된 텍스트만 출력하려면, -n 옵션과 함께 다음과 같은 sed 커맨드로 사용하면 됩니다.
cat pytorch_tutorials.html | sed -r -n 's/.*<a .*href="([^"]+)">.*/\1/p'
http:// 나 https:// 가 없는 링크는 html소스를 다운로드 받은 주소의 디렉토리인 https://pytorch.org/tutorials/ 가 앞에 생략했기 때문입니다.