2) 리눅스 명령어 grep, 원하는 라인만 출력하기

리눅스에서 grep은 대단히 유용하면서 자주 쓰이는 명령어 중에 하나이다.
본 포스팅에서는 수십~수백만 라인 중에서 사용자가 원하는 라인만 골라서 출력해주는 grep 명령어의 사용법에 대해서 알아본다.

수십~수백 줄의 문자열로 가득한 파일에서 내가 원하는 라인만 출력하는 것은 인력으로 어느 정도 가능한 일이지만 천 줄이 넘어가면서부터는 사람의 힘으로는 도저히 불가능한 작업이 된다. 여기서 ‘내가 원하는 라인‘이란 쉽게는 ‘내가 찾는 문자 또는 문자열이 들어있는 라인‘, 좀 더 복잡하게는 ‘내가 찾는 패턴이 들어있는 라인‘으로 정의할 수 있다.

내가 찾는 문자열이 들어간 라인 출력

그럼, grep 명령어를 가장 쉽게 사용하는 방법인 문자열 검색부터 소개해본다.

grep 명령어를 배우기 전 효과적인 grep을 쓰기 위한 기초 명령어를 알아본다.
리눅스 명령어 중 ‘ps’는 현재 실행되고 있는 프로세스의 상태를 출력한다. 터미널에 ps 라고만 입력 후 엔터를 치면 보통 대부분 다음 화면같이 나올 것이다.

[root@kaka]ps 
PID    TTY     TIME     CMD
13480  pts/0   00:00:00 bash 
13851  pts/0   00:00:00 ps

현재 터미널 쉘이 bash가 아니라면 다르게 나올 수도 있지만 큰 차이는 없을 것이다.
ps 명령어에는 보통 aux 옵션을 많이 사용한다. 각 옵션을 소개하자면,
a: 모든 사용자 프로세스 출력 옵션
u: 자세한 정보 출력
x: 제어터미널이 없는 프로세스도 출력
(정보 출처: http://finetia.egloos.com/1514615)

터미널에 ps aux라고 친 후 엔터를 누르면 수십, 수백 개의 프로세스 설명 리스트가 출력될 것이다.
문제는 여기서 발생한다.
수백 개의 리스트 중에서 내가 원하는 프로세스 설명만 출력할 순 없을까?
특정 프로세스 정보를 알아야 하는 경우, 이를테면 PID를 알아내서 강제종료해야 할 경우가 생길 수 있다. 이때 수백 줄이 넘는 프로세스 리스트를 일일이 눈으로 찾는 것은 너무 고달픈 일일 것이다.
여기서 바로 grep 명령어를 쓰면 모든 것이 해결된다.

만약 프로세스 정보 리스트(ps aux) 중에서 톰캣 프로세스를 찾고 싶을 경우는 다음과 같이 명령어를 사용하면 된다.

[root@kaka] ps aux | grep "tomcat"
root  14099  0.0  0.0  65344  840  pts/0  S+  18:48  0:00  grep tomcat
root  27472  0.6 54.6  176558 460448  ?   Sl  Nov29  19:36  /usr/local/java...(생략)

1: ps aux 명령 후 출력 리스트를 파이프 라인을 통해서 grep 명령어에 전달한다. grep 명령어에서는 input으로 들어오는 모든 라인 중에서 쌍따옴표 안에 있는 “tomcat” 이라는 문자열이 들어있는 라인을 출력한다.
2: ps aux 명령어는 실행 중인 모든 프로세스를 출력하기 때문에 1줄의 grep “tomcat” 조차도 출력한다. 따라서 1줄의 grep “tomcat” 명령어도 grep에 의해서 검색된다.
3: 우리가 찾고자 했던 프로세스 정보이다. PID, 실행시간, 실행 위치 등의 정보를 얻을 수 있다.

ps aux | grep “프로세스 관련 문자열” 조합은 실제 작업 중에서 빈번하게 사용된다. 특히 특정 프로세스를 찾아서 강제종료하고 싶은 경우가 많이 발생하는데 이때 유용하게 사용이 가능하다.

내가 찾는 패턴이 들어있는 라인 출력

단순 문자열 검색에 비해 좀 더 강력한 방법이다.

내가 찾는 패턴‘의 예를 들어보면 다음과 같다.
Christmas
X-Mas
Mascherano
위 세 라인이 test.txt라는 파일에 저장되어 있다고 했을 때,
test.txt 파일에서 크리스마스와 관련된 라인만 출력하고 싶은 경우가 생겼다. ‘Christmas’, ‘X-Mas’가 그 대상이다.
두 문자열 모두 ‘mas’가 들어가지만 1번째 줄의 mas는 전부 소문자이지만, 2번째 줄의 Mas는 ‘M’이 대문자이다.
따라서 grep "mas" test.txt로 치면 1번째 줄만 검색되고, grep "Mas" test.txt로 치면 2,3번째 줄이 출력된다.
명확히 출력하고자 하는 라인은 1,2번째 줄이기 때문에 단순 문자열 검색만으로는 가능하지 않다.

지금 첫 번째 문제는 1번째 줄과 2번째 줄의 ‘mas-Mas’의 대소문자 구분이고 두 번째 문제는 2번째 줄과 3번째 줄이 동일하게 ‘Mas’를 포함하고 있다는 것이다.

첫 번째 문제는 grep의 ‘-i’ 옵션을 사용하면 된다. -i 옵션은 대소문자를 구분하지 않고 검색한다는 의미이다.

[root@kaka] grep -i "mas" test.txt
Christmas
X-Mas
Mascherano

위와 같이 -i 옵션을 사용할 경우 ‘mas’와 ‘Mas’를 구분하지 않고 동일하게 취급한다. 뿐만 아니라 ‘MAS’, ‘mAs’, ‘MAs’와 같은 형태도 모두 검색된다.

첫 번째 문제를 해결했으니 두 번째 문제로 넘어가보자.
1,2번째 줄과 3번째 줄의 차이점은 ‘Mas’가 가장 뒤에 오느냐, 아니면 앞에 오느냐이다. 1,2번째 줄은 문자열의 맨 마지막에 오지만 3번째 줄은 가장 앞에 ‘Mas’가 위치한다.
이를 패턴화시켜 grep 에 사용해 볼 수 있다.

여기서 정규표현식이란 개념이 등장한다. 정규표현식에서 가장 중요한 것이 바로 ‘패턴’, ‘규칙’을 찾는 것이다. 정확한 규칙을 찾아 정규표현식의 문법에 맞게 작성만 하면 그 어떤 문자열도 찾아낼 수 있다.

정규표현식에서 모든 문자를 표현하는 게 바로 ‘.'(온점)이다. 여기서 주의할 점은 문자열이 아닌 문자라는 것이다. 이를 위 세 개 example에 적용해보자

1번째 줄의 Christmas에서 ‘tmas’는 ‘.mas’로 패턴화시킬 수 있다.
2번째 줄의 X-Mas에서 ‘-Mas’역시 ‘.mas’로 패턴화시킬 수 있다.
하지만 3번째 줄의 Mascherano에서는 ‘.mas’로 패턴화시킬 수 없다. ‘Mas’가 가장 앞에 오기 때문이다.

이를 이용하여 grep 명령어에 사용해보면 다음과 같다.

[root@kaka] grep -i -e ".mas" test.txt
Christmas
X-Mas

1: grep 옵션 중 -e 옵션은 정규표현식을 사용한다는 의미이다. -i(대소문자 구분x), -e(정규표현식 사용) 옵션이 사용된 것이다.
2~3: 처음에 의도했던 결과대로 출력이 된 것을 확인할 수 있다.

정규표현식은 grep 명령어 뿐만 아니라 awk, find 명령어 에서도 빈번하게 사용된다. 또한 리눅스 명령어 외에도 다른 다양한 프로그래밍 언어에서 지원하고 있기 때문에 사용법만 익힌다면 획기적인 생산성 향상을 이뤄낼 수 있다. 정규표현식을 쓰지 않고 특정 패턴을 포함하는 문자열을 찾는 것은 가능하긴 하지만 확실히 비효율적인 부분이 많게 된다.

grep 명령어의 두 가지 옵션을 알아봤는데 이외에도 많은 다양한 옵션이 있으니 찾아보면 좋을 것이다.
-i, -e와 많이 쓰이는 것이 -v 옵션인데 이는 쌍따옴표 내부의 문자열 또는 문자열 패턴을 포함하지 않는 라인만 출력한다.
-v 옵션을 사용하여 우리가 원하는 라인(1,2)만 출력하고자 한다면 다음과 같이 할 수 있다.

[root@kaka] grep -v -i -e "mas." test.txt
Christmas
X-Mas

1: grep -i -e “mas.” text.txt의 결과 값이 Mascherano이기 때문에 -v 옵션을 주면 Mascherano를 제외한 다른 라인이 출력된다.
2~3: 처음에 의도했던 결과대로 출력이 된 것을 확인할 수 있다.

Leave a comment