grep·sed·awk·vi·JavaPattern이 공통으로 쓰는 정규식 문법을 한 장에 모았습니다. 도구마다 다른 부분(BRE·ERE·PCRE·Java)을 표로 나누고, 로그·IP·날짜·이메일처럼 실무에서 반복되는 패턴을 바로 복사해 쓸 수 있게 정리했습니다. 운영 묶음 02 텍스트 처리와 자바 초급 문자열 레슨의 참조 페이지입니다.
| 문법 | 뜻 | 예 |
|---|---|---|
. |
아무 글자 하나 | a.c → abc, a1c |
* |
0개 이상 | ab* → a, ab, abbb |
+ |
1개 이상 | ab+ → ab, abbb |
? |
0개 또는 1개 | colou?r |
{n} {n,m} |
개수 | [0-9]{3} |
[abc] [a-z] |
글자 집합·범위 | [0-9] |
[^abc] |
집합 제외 | [^ ]+ 공백 아닌 것 |
^ $ |
줄 처음·끝 | ^ERROR, ms$ |
| |
또는 | ERROR|WARN |
( ) |
그룹 | (ab)+ |
\1 |
그룹 역참조 | (a)\1 → aa |
\. |
메타 문자 자체 | \.log |
\d \w \s |
숫자·단어·공백 | PCRE·Java |
\b |
단어 경계 | \bERROR\b |
| 기능 | grep 기본 (BRE) | grep -E / sed -E / awk (ERE) | grep -P / Java |
|---|---|---|---|
| 또는 | | |
| 없이 a|b |
같음 |
| 1개 이상 | \+ |
+ |
+ |
| 그룹 | \( \) |
( ) |
( ) |
| 개수 | \{3\} |
{3} |
{3} |
\d \w \s |
없음 | 없음 ([0-9] 사용) |
있음 |
최소 일치 *? |
없음 | 없음 | 있음 |
| 앞뒤 조건 확인 | 없음 | 없음 | 있음 |
BRE 에서는 +·?·|·( )·{ } 가 글자 그대로이고 역슬래시를 붙여야 메타가 됩니다. 헷갈리면 항상 -E 를 쓰는 것이 간단합니다. \d 는 grep -E 에서 안 되므로 [0-9] 로 씁니다.
grep 'ERROR\|WARN' f # BRE: \| 필요
grep -E 'ERROR|WARN' f # ERE: 그대로
grep -P '\d{4}-\d{2}' f # PCRE: \d 사용
sed -E 's/([0-9]+)ms/\1 ms/' f
awk '/^[0-9]{4}-/' f| 집합 | 뜻 | 대응 |
|---|---|---|
[0-9] |
숫자 | \d, [[:digit:]] |
[a-zA-Z] |
영문 | [[:alpha:]] |
[a-zA-Z0-9_] |
단어 글자 | \w, [[:alnum:]_] |
[ \t] |
공백·탭 | \s, [[:space:]] |
[^0-9] |
숫자 아닌 것 | \D |
[.] |
점 자체 | \. |
[]] |
] 자체 |
집합 맨 앞에 |
[a-] |
- 자체 |
집합 맨 끝에 |
[[:digit:]] 계열은 모든 도구에서 동작하고 한글 로케일에서도 안전합니다. 집합 안에서는 .·*·+ 가 메타가 아닙니다.
^·$·\b 는 글자를 소비하지 않고 위치만 맞추는 표기입니다. 영어로는 anchor(닻)라고 부릅니다.
| 표기 | 뜻 | 예 |
|---|---|---|
^ |
줄 처음 | ^2026- 날짜로 시작 |
$ |
줄 끝 | ms$ |
^$ |
빈 줄 | grep -v '^ |
^\s*# |
주석 줄 | grep -vE '^\s*(#|$)' |
\b |
단어 경계 | \bat\b (cat 제외) |
\< \> |
단어 시작·끝 | grep·vi |
^ 와 $ 를 붙이면 줄 전체 일치입니다. 설정 파일에서 ^server.port= 처럼 키를 앞에 고정해야 management.server.port 가 걸리지 않습니다.
{n,m}·*·+ 는 바로 앞 글자를 몇 번 반복할지 정합니다. 반복은 기본적으로 가능한 한 길게 잡으며(최대 일치, greedy), *? 처럼 ? 를 붙이면 가능한 한 짧게 잡습니다(최소 일치, lazy).
| 표기 | 뜻 |
|---|---|
a{3} |
정확히 3 |
a{2,} |
2 이상 |
a{1,3} |
1~3 |
a* |
0 이상, 가능한 많이 |
a*? |
0 이상, 가능한 적게 (PCRE·Java) |
.* 는 최대 일치(가능한 한 길게 잡음)라 "(.*)" 는 첫 따옴표부터 마지막 따옴표까지 잡습니다. ERE 에는 최소 일치 *? 가 없으므로 "([^"]*)" 처럼 "따옴표 아닌 것" 집합으로 씁니다. 이 형태가 어느 도구에서나 동작해 실무에서는 이쪽을 권합니다.
sed -E 's/^([0-9-]+) ([0-9:]+) /\2 /' f # 날짜 떼고 시각만
sed -E 's/(\w+)@(\w+)\.com/\2:\1/' f # 그룹 순서 바꾸기
grep -E '(ab)\1' f # abab
grep -oE '^[a-z]+\.([a-zA-Z]+\.)+[A-Za-z]+Exception' f # 예외 클래스| 도구 | 치환에서 그룹 참조 |
|---|---|
| sed | \1 \2 |
| awk | gensub(/(a)(b)/, "\\2\\1", "g") |
| vi | \1 |
| Java | $1 $2 |
| Perl·PCRE | $1 또는 \1 |
(?:...) 는 참조 번호를 만들지 않는 그룹으로 PCRE·Java 에서 씁니다. (?<name>...) 이름 그룹은 Java 에서 m.group("name") 으로 꺼냅니다.
| 대상 | 패턴 (ERE) |
|---|---|
| 날짜 | [0-9]{4}-[0-9]{2}-[0-9]{2} |
| 시각 | [0-9]{2}:[0-9]{2}:[0-9]{2} |
| IPv4 | ([0-9]{1,3}\.){3}[0-9]{1,3} |
| 포트 붙은 IP | ([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]+ |
| 이메일 | [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,} |
| 전화번호 | 01[0-9]-?[0-9]{3,4}-?[0-9]{4} |
| URL 경로 | /api/[a-z]+(/[0-9]+)? |
| HTTP 상태 | (2|3|4|5)[0-9]{2} |
| 응답 시간 | [0-9]+ms |
| 로그 레벨 | (TRACE|DEBUG|INFO|WARN|ERROR) |
| 자바 예외 | [a-z]+(\.[A-Za-z]+)+(Exception|Error) |
| jar 버전 | [0-9]+\.[0-9]+\.[0-9]+ |
| UUID | [0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12} |
| 주석·빈 줄 제외 | ^\s*(#|$) (-v 로) |
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log | sort | uniq -c | sort -rn | head # IP 상위
grep -oE '/api/[a-z]+' app.log | sort | uniq -c | sort -rn # 경로 빈도
grep -E ' 5[0-9]{2} ' app.log # 5xx
grep -oE '[a-z]+(\.[A-Za-z]+)+Exception' app.log | sort | uniq -c | sort -rn # 예외 종류
sed -E 's/(password=)[^ ]+/\1****/' app.log # 마스킹
awk '/^[0-9]{4}-/ && $3=="ERROR"' app.log # 날짜 줄 중 ERROR| 형태 | 뜻 |
|---|---|
s/a/b/ |
줄마다 첫 번째 |
s/a/b/g |
전부 |
s/a/b/2 |
두 번째만 |
s/a/b/gi |
대소문자 무시 |
s#/a#/b# |
구분자 변경 |
/패턴/s/a/b/ |
패턴 줄에서만 |
10,20s/a/b/ |
줄 범위 |
s/.*/[&]/ |
& 는 일치 전체 |
sed -E 's/^([^=]+)=.*/\1=****/' env # 모든 값 가리기
sed -E 's/[[:space:]]+$//' f # 줄 끝 공백 제거
sed -E 's/^[[:space:]]+//' f # 줄 앞 공백 제거
sed -n -E '/^(server|logging)\./p' f # 두 접두 키만awk '/ERROR/' f # 줄 일치
awk '$3 ~ /^(ERROR|WARN)$/' f # 열 일치
awk '$6 !~ /^\/health/' f # 열 불일치
awk 'match($0, /[0-9]+ms/) {print substr($0, RSTART, RLENGTH)}' f # 일치 부분 추출
awk '{gsub(/[0-9]{1,3}(\.[0-9]{1,3}){3}/, "x.x.x.x"); print}' f # 치환
awk -F'[=:]' '{print $1}' f # 구분자를 정규식으로~ 가 일치, !~ 가 불일치입니다. -F 에 집합을 주면 여러 구분자를 한 번에 씁니다. gawk 는 gensub 로 그룹 참조 치환이 됩니다.
| 명령 | 뜻 |
|---|---|
/패턴 ?패턴 |
아래·위 검색 |
n N |
다음·이전 |
:%s/a/b/g |
전체 치환 |
:%s/a/b/gc |
확인하며 |
:5,20s/a/b/ |
줄 범위 |
:g/패턴/d |
패턴 줄 삭제 |
:v/패턴/d |
패턴 없는 줄 삭제 |
\v |
very magic, ERE 처럼 |
vi 기본은 BRE 라 +·(·| 에 역슬래시가 필요합니다. :%s/\v(a|b)+/x/g 처럼 \v 를 앞에 붙이면 ERE 문법이 됩니다. :%s/old/new/gc 의 c 가 하나씩 확인입니다.
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2026-09-11 ERROR");
if (m.find()) System.out.println(m.group(1) + "/" + m.group(2)); // 2026/09
"a1b22c333".replaceAll("\\d+", "#"); // a#b#c#
"a,b;c".split("[,;]"); // [a, b, c]
Pattern.matches("^[0-9]{3}$", "123"); // 전체 일치
Pattern.compile("error", Pattern.CASE_INSENSITIVE);
Pattern.compile("(?<y>\\d{4})-(?<m>\\d{2})"); m.group("y"); // 이름 그룹| 항목 | Java 특징 |
|---|---|
| 역슬래시 | 문자열 안이라 \\d 두 번 |
matches |
전체 일치, find 는 부분 |
$1 |
replaceAll 치환 참조 |
Pattern.quote(s) |
메타 문자 이스케이프 |
(?i) (?m) (?s) |
대소문자 무시·여러 줄·점이 줄바꿈 포함 |
| 컴파일 재사용 | 루프 안 compile 금지, static 으로 |
String.matches 는 매번 컴파일하므로 반복 호출 시 Pattern 을 static 으로 두고 재사용합니다. 사용자 입력을 정규식에 넣을 때는 Pattern.quote 로 감쌉니다.
본문에 넣지 않고 앞뒤에 특정 글자가 있는지만 확인하는 표기입니다. 영어로는 lookahead(뒤 확인)·lookbehind(앞 확인)라고 부릅니다.
| 표기 | 뜻 | 예 |
|---|---|---|
(?=x) |
뒤에 x 가 옴 | \d+(?=ms) 숫자만 |
(?!x) |
뒤에 x 가 안 옴 | ERROR(?! ignored) |
(?<=x) |
앞에 x 가 있음 | (?<=port=)\d+ |
(?<!x) |
앞에 x 가 없음 |
grep -oP '(?<=port=)\d+' app.properties # 값만
grep -oP '\d+(?=ms)' app.log | sort -n | tail -n 3 # 응답 시간 상위grep -P 와 Java 에서만 됩니다. sed·awk 에서는 그룹으로 잡아 \1 로 꺼내는 방식으로 대신합니다.
| 상황 | 방법 |
|---|---|
| 셸에서 패턴 | 작은따옴표 '...' 로 감싸기 |
패턴 안 / |
sed 's#a/b#c#' 구분자 변경 |
| 점 자체 | \. 또는 [.] |
| 변수 포함 | grep "$VAR" 큰따옴표, 메타 주의 |
| 고정 문자열 | grep -F '1.2.3' 정규식 해석 안 함 |
| Java 문자열 | \\ 두 번, 또는 Pattern.quote |
| 사용자 입력 | grep -F 또는 Pattern.quote |
정규식이 아니라 문자열을 찾을 때는 grep -F 가 빠르고 안전합니다. IP 10.0.0.1 을 정규식으로 찾으면 10x0y0z1 도 걸리므로 -F 나 \. 이 필요합니다.
| 실수 | 결과 | 바른 형태 |
|---|---|---|
| `grep 'a | b'` | 글자 그대로 |
grep -E '\d' |
안 됨 | [0-9] |
grep app.log |
appXlog 도 |
app\.log |
".*" 최대 일치 |
끝까지 | "[^"]*" |
[a-Z] |
오류·이상 범위 | [a-zA-Z] |
^ 없이 키 검색 |
xserver.port 도 |
^server.port= |
$VAR 작은따옴표 |
확장 안 됨 | "$VAR" |
Java "\d" |
컴파일 오류 | "\\d" |
String.matches 반복 |
매번 컴파일 | Pattern static |
루프 안 .* 중첩 |
매우 느림 | 글자 집합·위치 표기로 좁히기 |
echo 'test 2026-09-11' | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' # 바로 시험
echo 'abc' | sed -E 's/(b)/[\1]/' # 그룹 확인
grep -cE '패턴' f # 몇 줄 걸리나
grep -nE '패턴' f | head # 어디에 걸리나새 패턴은 echo | grep -o 로 먼저 시험하고 파일에 적용합니다. -c 로 개수를 보고 -n | head 로 표본을 확인한 뒤 sed -i 나 -delete 에 붙입니다. Java 는 JShell 에서 Pattern.compile(...).matcher(...).find() 로 같은 확인을 합니다.