Computer >> 컴퓨터 >  >> 프로그래밍 >> Bash 프로그래밍

고급 sed 치환 기법 완벽 가이드: 구분자, & 참조, 그룹화와 역참조 실전 예제

고급 sed 치환 기법 완벽 가이드: 구분자, & 참조, 그룹화와 역참조 실전 예제이 글은 유닉스(Unix) sed 팁 & 트릭 시리즈의 연재 글입니다.

이전 sed 연재 글에서는 sed 출력, 삭제, 치환(substitute), 파일 쓰기, 다중 명령 사용법을 차례로 살펴보았습니다.

이번 글에서는 sed의 's' 치환 명령어를 활용한 흥미로운 응용 기법들을 여러 실전 예제와 함께 정리해 보겠습니다.

1. sed 치환 구분자(Delimiter)

이전 포스트에서 다루었듯이, sed 치환 명령어에서는 @ % | ; : 와 같은 다양한 구분자를 사용할 수 있습니다.

먼저 아래 예제들에서 공통으로 사용할 path.txt 파일을 생성하겠습니다.

$ cat path.txt
/usr/kbos/bin:/usr/local/bin:/usr/jbin:/usr/bin:/usr/sas/bin
/usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin:
/opt/omni/lbin:/opt/omni/sbin:/root/bin

예제 1 – @ 구분자 사용: /opt/omni/lbin을 /opt/tools/bin으로 치환

'/'가 포함된 경로 이름을 치환할 때는 '/' 대신 @를 구분자로 사용하면 편리합니다. 아래 sed 예제에서는 입력 파일의 마지막 줄에 있는 /opt/omni/lbin이 /opt/tools/bin으로 변경되었습니다.

$ sed 's@/opt/omni/lbin@/opt/tools/bin@g' path.txt
/usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin:/usr/sas/bin
/usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin:
/opt/tools/bin:/opt/omni/sbin:/root/bin

예제 2 – / 구분자 사용: /opt/omni/lbin을 /opt/tools/bin으로 치환

경로 관련 치환에서 반드시 '/'를 구분자로 사용해야 한다면, 아래와 같이 치환 데이터 내부의 '/'를 이스케이프(escape) 처리해야 합니다. 이 예제에서는 REGEXP 부분과 REPLACEMENT 부분에서 구분자 '/'가 모두 이스케이프되었습니다.

$ sed 's/\/opt\/omni\/lbin/\/opt\/tools\/bin/g' path.txt
/usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin:/usr/sas/bin
/usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin:
/opt/tools/bin:/opt/omni/sbin:/root/bin

2. sed '&' – 매칭된 문자열 활용하기

&는 입력 줄에서 정규 표현식이 매칭된 정확한 부분을 나타내며, 치환(replacement) 부분에서 재활용할 수 있습니다.

예제 1 – & 활용: /usr/bin/을 /usr/bin/local로 치환

$ sed 's@/usr/bin@&/local@g' path.txt
/usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin/local:/usr/sas/bin
/usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin/local:/opt/omni/bin:
/opt/omni/lbin:/opt/omni/sbin:/root/bin

위 예제에서 치환 부분의 '&'는 매칭된 패턴인 /usr/bin으로 대체되고, 그 뒤에 /local이 붙습니다. 따라서 출력 결과에서 /usr/bin이 등장하는 모든 부분이 /usr/bin/local로 변경됩니다.

예제 2 – & 활용: 줄 전체 매칭

&는 주어진 REGEXP와 일치하는 모든 내용을 그대로 대체합니다.

$ sed 's@^.*$@<<<&>>>@g' path.txt
<<</usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin:/usr/sas/bin>>>
<<</usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin:>>>
<<</opt/omni/lbin:/opt/omni/sbin:/root/bin>>>

위 예제의 정규 표현식 '^.*$'은 줄 전체와 매칭됩니다. 치환 부분인 <<<&>>>는 줄 전체의 맨 앞과 맨 뒤에 각각 <<<와 >>>를 붙여 출력합니다.

3. sed에서 그룹화(Grouping)와 역참조(Back-reference)

sed에서도 일반 정규 표현식처럼 그룹화를 사용할 수 있습니다. 그룹은 '\(' 로 열고 '\)' 로 닫으며, 역참조(back-reference)와 조합하여 활용할 수 있습니다.

역참조란 그룹화로 선택된 정규 표현식의 일부를 재사용하는 것을 의미합니다. sed의 역참조는 정규 표현식 자체와 치환 명령의 replacement 부분 양쪽에서 모두 사용할 수 있습니다.

예제 1: 각 줄에서 첫 번째 경로만 추출하기

$ sed 's/\(\/[^:]*\).*/\1/g' path.txt
/usr/kbos/bin
/usr/local/sbin
/opt/omni/lbin

위 예제에서 \(\/[^:]*\)는 첫 번째 ':'이 나오기 전까지의 경로와 매칭됩니다. \1은 첫 번째로 매칭된 그룹으로 대체됩니다.

예제 2: 다중 그룹(Multigrouping) 활용

path.txt 파일의 마지막 줄에서 필드 순서를 변경해 보겠습니다.

$ sed '$s@\([^:]*\):\([^:]*\):\([^:]*\)@\3:\2:\1@g' path.txt
/usr/kbos/bin:/usr/local/bin:/usr/jbin:/usr/bin:/usr/sas/bin
/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/omni/bin:
/root/bin:/opt/omni/sbin:/opt/omni/lbin

위 명령에서 $는 치환이 마지막 줄에만 적용되도록 지정하는 역할을 합니다. 출력 결과를 보면 마지막 줄의 경로 값 순서가 뒤바뀐 것을 확인할 수 있습니다.

예제 3: /etc/passwd 파일에서 사용자 이름 목록 추출하기

이 sed 예제는 /etc/passwd 파일에서 첫 번째 필드(사용자 이름)만 추출하여 출력합니다.

$sed 's/\([^:]*\).*/\1/' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown

예제 4: 각 단어의 첫 글자를 괄호로 묶기

이 sed 예제는 문장 내 모든 단어의 첫 글자를 괄호로 감싸서 출력합니다.

$ echo "Welcome To The Geek Stuff" | sed 's/\(\b[A-Z]\)/\(\1\)/g'
(W)elcome (T)o (T)he (G)eek (S)tuff

예제 5: 숫자에 천 단위 콤마 넣기

먼저 숫자 목록이 담긴 numbers 파일을 생성합니다. 아래 sed 명령은 최대 4자리 숫자까지 천 단위 콤마를 추가해 줍니다.

$ cat numbers
1234
12121
3434
123
$sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers
1,234
12,121
3,434
123

마무리

지금까지 sed의 's' 치환 명령어에서 활용할 수 있는 구분자 변경, &를 이용한 매칭 문자열 재사용, 그룹화와 역참조 기법을 살펴보았습니다. 이러한 기법들을 조합하면 복잡한 텍스트 변환 작업도 단 한 줄의 명령으로 손쉽게 처리할 수 있습니다. 다음 연재 글에서도 더욱 실용적인 sed 활용법을 소개하겠습니다.