텍스트 조작 마스터하기: 개발자를 위한 Regex, Grep, Sed, Awk 가이드
Source: Dev.to
번역을 진행하려면 번역하고자 하는 전체 텍스트를 제공해 주시기 바랍니다. 현재는 링크만 제공되어 있어 실제 내용이 없으므로 번역을 수행할 수 없습니다. 텍스트를 복사해서 붙여 주시면 바로 한국어로 번역해 드리겠습니다.
소개: 한눈에 보는 유닉스 철학
현대 소프트웨어 개발은 복잡한 툴체인과 IDE가 특징이지만, 겸손한 커맨드 라인은 여전히 강력함과 효율성의 견고한 요새로 남아 있습니다. 터미널에서 직접 텍스트를 조각하고, 검색하고, 변형하는 능력은 과거의 기술이 아니라, 숙련된 개발자와 진정한 장인 사이를 구분 짓는 영원한 기술입니다. 이 힘은 유닉스 철학에 뿌리를 두고 있습니다: 각각 하나의 일을 잘 수행하도록 설계된 작고 전문화된 도구들의 집합. 이 도구들을 체인처럼 연결하면 복잡한 작업도 우아하고 명확하게 수행할 수 있습니다.
이 가이드는 텍스트 조작을 위한 기본 툴킷을 실용적이고 직접적인 투어 형태로 제공합니다. 먼저 정규 표현식(regex) — 텍스트 내 패턴을 기술하는 보편적인 언어 — 에 대해 시작합니다. 그 다음, 이 언어에 생명을 불어넣는 세 가지 핵심 유틸리티를 살펴볼 것입니다: grep, 궁극적인 파일 검색기; sed, 번개처럼 빠른 스트림 편집기; 그리고 awk, 구조화된 데이터를 위한 강력한 레코드 프로세서. 우리의 목표는 모든 것을 포괄하는 것이 아니라, 매일 마주하게 될 텍스트 처리 과제의 80 %를 해결할 수 있는 필수 지식을 제공하는 것입니다.
1. 패턴의 언어: 정규 표현식 (Regex) 빠른 입문
도구를 다루기 전에 먼저 언어를 배워야 합니다. 정규 표현식은 텍스트 검색 패턴을 지정하기 위한 형식적인 구문입니다. 이것을 특정 프로그램의 기능이라기보다, 명령줄 유틸리티와 텍스트 편집기부터 Python, JavaScript 같은 프로그래밍 언어에 이르기까지 모든 곳에서 고급 기능을 열어주는 이식 가능한 기본 기술이라고 생각하세요. 정규 표현식의 핵심 개념을 마스터하는 것은 여러분의 전체 경력에 걸쳐 큰 이익을 가져다 줍니다.
1.1. 핵심 구성 요소
정규 표현식은 문자들의 연속이며, 그 중 일부는 리터럴(자기 자신과 일치)이고, 일부는 메타문자(특별한 의미를 가짐)입니다. 가장 기본적인 메타문자는 단일 문자 매치, 반복, 그리고 라인 내 위치를 제어합니다.
이 예시들은 확장 정규 표현식 (ERE) 을 사용하여 설명합니다. 일부 도구가 기본으로 사용하는 오래된 기본 정규 표현식 (BRE) 구문과의 중요한 차이점은 1.3절에서 다룹니다.
1.2. 문자 집합 지정 (문자 클래스)
대부분의 경우, 단순히 “어떤 문자든”이 아니라 특정 집합에 속하는 문자와 매치하고 싶습니다. 대괄호 표현식 [...] 은 이러한 “문자 클래스”를 정의하는 주요 메커니즘입니다.
-
특정 목록 매치 – 매치하고 싶은 정확한 문자를 나열합니다.
예시:[aeiou]는 소문자 모음 하나와 매치됩니다. -
범위 매치 – 두 문자 사이에 하이픈(
-)을 넣으면 시스템의 정렬 순서에 따라 그 사이의 모든 문자를 포함하는 범위가 만들어집니다.
예시:[a-z]는 ASCII 기반 시스템에서 소문자 알파벳 하나와 매치됩니다.
Note: 범위의 동작은 시스템의 언어 설정(로케일)에 크게 의존합니다.
[a-z]가 문자들이 연속된 ASCII에서는 예측 가능하게 동작하지만, 다른 로케일에서는a, A, b, B, …와 같이 대소문자가 섞여 정렬될 수 있습니다. 이런 로케일에서는[a-c]가 의도한a, b, c대신a, A, b, B, c와 매치될 수 있습니다. 이는 POSIX 문자 클래스 섹션에서 해결할 중요한 함정입니다.
- 집합 부정 – 대괄호 안 첫 번째 문자로 케어트(
^)를 사용하면 매치를 부정하여, 해당 집합에 속하지 않는 모든 단일 문자와 매치됩니다.
예시:[^0-9]는 숫자가 아닌 모든 문자와 매치됩니다.
1.3. 큰 구분: 기본 vs. 확장 정규식 (BRE vs. ERE)
명령줄에 익숙하지 않은 개발자들이 가장 흔히 겪는 혼란 중 하나는 두 가지 약간 다른 정규식 구문이 존재한다는 점입니다. 이는 Unix 발전 과정에서 생긴 역사적 산물입니다.
-
기본 정규 표현식 (BRE) – 원래의 오래된 구문.
grep,sed와 같은 유틸리티가 기본으로 사용합니다. BRE에서는+,?,|,()같은 많은 메타문자가 특별한 의미를 잃고, 백슬래시(\)로 이스케이프해야만 기능을 발휘합니다. -
확장 정규 표현식 (ERE) – 더 현대적이고 가독성이 좋은 구문으로, 특수 문자를 이스케이프할 필요가 없습니다.
egrep(또는grep -E)와awk가 이 구문을 사용합니다.
차이는 미묘하지만 결정적입니다:
Pro Tip: 새 스크립트를 작성할 때는
grep -E혹은sed -E로 확장 구문을 기본으로 사용하세요. BRE는 오래된 스크립트를 읽기 위해 이해해야 하는 역사적 산물일 뿐, 현대적이고 가독성 높은 작업에서는 ERE가 표준입니다. 새 스크립트를 BRE로 작성할 합당한 이유는 거의 없습니다.
패턴 언어를 이해했으니, 이제 가장 유명한 파트너인 grep 과 함께 사용하는 방법을 살펴봅시다.
Source: …
2. grep으로 건초 더미에서 바늘 찾기
grep(Global Regular Expression Print)은 전형적인 명령줄 검색 도구입니다. 그 목적은 단순하지만 깊이 있습니다: 입력을 한 줄씩 읽고 주어진 패턴과 일치하는 줄만 출력합니다. 이 때문에 디버깅, 로그 파일 분석, 익숙하지 않은 코드베이스 탐색 등에 없어서는 안 될 도구가 됩니다.
2.1. 실용적인 검색 작업
이제 이론에서 벗어나 몇 가지 흔한 grep 사용 사례를 살펴보겠습니다.
예제 1: 로그 파일에서 IP 주소 검색
특정 IP 주소를 찾으려면 .이 와일드카드이므로 점을 이스케이프해야 합니다. \b를 사용해 단어 경계를 지정하면 더 큰 숫자 문자열의 일부와 일치하는 것을 방지할 수 있습니다(예: 101.10.3.20).
grep '\b1\.10\.3\.20\b' logfile.log
전문가 메모: 단어 경계 앵커
\b는 강력한 GNU 확장이지만 POSIX 표준에 포함되지 않아 모든 시스템에서 사용할 수 있는 것은 아닙니다. 전체 단어와 일치시키는 진정한 이식 가능한 방법은 경계가 무엇인지 명시적으로 정의하는 것입니다—보통 공백 문자이거나 행의 시작·끝입니다. 예를 들어, “book”이라는 단어를 찾는 견고한 패턴은 다음과 같이 작성할 수 있습니다:
grep '(^|[[:space:]])book([[:space:]]|$)' file.txt
2.2. 역참조의 힘
패턴의 일부를 괄호 (...)(또는 BRE에서는 \(...\)) 로 감싸면 캡처 그룹이 생성됩니다. n번째 그룹이 매치한 텍스트는 이후에 \n으로 참조할 수 있습니다.
예제
grep '^\(.*\)\1$' /usr/share/dict/words
가능한 출력
adad
beriberi
chichi
또 다른 고전적인 예:
egrep -v '^(11+)\1+$'
이 명령은 일진법으로 표현된 소수를 걸러냅니다.
3. 이식성 및 국제화: POSIX 문자 클래스
[a-z]와 같은 정규식은 비‑ASCII 로케일에서 깨질 수 있습니다. POSIX 문자 클래스는 다음과 같은 로케일 인식 집합을 통해 이를 해결합니다:
[[:digit:]][[:alpha:]][[:space:]]
3.2. 심층 분석: [0-9] vs. [[:digit:]] vs. \d
| Pattern | Scope |
|---|---|
[0-9] | ASCII 전용 |
[[:digit:]] | POSIX 이식 가능(로케일 인식) |
\d | PCRE / Unicode 환경 전용 |
3.3. 성능 비결: LC_ALL=C
export LC_ALL=C
grep 'some_pattern' huge_logfile.txt
LC_ALL=C를 설정하면 ASCII 모드가 강제되고 처리 속도가 크게 빨라질 수 있습니다.
4. 실시간 텍스트 변환 with sed
sed는 스트림 편집기입니다.
4.1. 치환 구문
s/pattern/replacement/flags
&= 전체 매치\1= 첫 번째 캡처 그룹g= 모든 매치를 교체
4.2. sed 사용 예시
일반적인 사용 사례는 다음과 같습니다:
- 이름 재포맷
- C++ 주석 제거
- 각 줄을 따옴표로 감싸기
5. awk 로 데이터 슬라이싱 및 다이싱
awk는 입력을 레코드와 필드로 취급합니다.
5.1. 모델
pattern { action }
주요 변수:
$0— 전체 라인$1— 첫 번째 필드NF— 필드 개수
5.2. 예시: /etc/passwd
awk -F: '$3 > 1000 { print $1 }' /etc/passwd
6. 최종 정리: 정규식 vs. 셸 글로빙
*.txt는 정규 표현식이 아닙니다; 셸이 파일 이름 확장을 위해 사용하는 글로브 구문입니다.
결론: 당신의 명령줄 툴킷
grep— 검색sed— 변환awk— 구조화된 데이터를 처리