Logo

Globs (Glob Patterns) 문법 정리

이번 포스팅에서는 Glob Patterns, 흔히 줄여서 Globs라고 불리는 패턴 매칭에 대해서 알아보도록 하겠습니다.

Globs(Glob Patterns)란?

Globs은 오래전부터 리눅스 운영체제에서 한 번에 여러 개의 파일을 찾을 때 사용해온 패턴 매칭 기법인데요. 많은 리눅스 명령어가 인자로 Glob 패턴을 받기 때문에 알게 모르게 많이 사용하고 있으실 거에요. 예를 들어, 터미널에서 ls src/*.java와 유사한 커맨드를 날려보신 적이 있으시면 이미 어느정도 Globs 문법을 자연스럽게 체득하셨다고 볼 수 있을 것 같습니다.

Glob 패턴 매칭은 현재 리눅스 뿐만 아니라 Shell, Java, Python, NodeJS, Go, Ruby, PHP 등 대부분의 프로그래밍 언어에서 지원하고 있는데요. 특히, 운영 체제와 프로그래밍 언어를 가리지 않고 프레임워크나 라이브러리를 설정할 때 광범위하게 사용되고 있습니다. 주로 설정 내용을 프로젝트 내의 일부 파일에만 적용하고 싶을 때 Globs가 사용되는데요. 대표적인 사례로, Git에서 코드 저장소(repository) 내에 일부 파일을 추적하지 않기 위해서 사용하는 .gitignore 파일을 들 수 있겠습니다.

또한 개발자들이 거의 매일 사용하는 코드 편집기에서도 Globs가 사용되는 것을 쉽게 볼 수 있는데요. 예를 들어, VSCode에서 파일 검색할 때, 검색 범위에 일부 파일을 포함하거나 제외시킬 수 있는 기능이 있는데 이 때도 Globs 문법으로 패턴을 입력하도록 되어있습니다. (관련 매뉴얼)

그럼 지금부터 Globs에서 어떤 와일드카드(wildcard, 특수 기호/괄호)를 제공하고 어떻게 활용하는지에 대해서 함께 살펴볼까요?

? 기호

Glob 패턴에서 ? 기호는 문자의 종류와 상관없이 정확히 한 글자와 매칭이되는데요. 예를 들어 a?라는 패턴으로는 ab, ac, ad 등과 같은 이름의 파일을 찾을 수 있습니다. 하지만 abcabab 등과 같은 이름을 가진 파일은 찾을 수 없을 것입니다.

? 기호는 연달아 사용할 수도 있는데요. 예를 들어, data/ma??.txt라는 패턴으로는 data/main.txt, data/math.txt, data/mail.txt 등과 같은 이름의 파일을 찾을 수 있을 것입니다. 하지만 data/map.txtdata/maple.txt 등과 같은 이름을 가진 찾아지지 않겠죠?

? 기호는 아무래도 매칭 범위가 짧다보니 그렇게 자주 사용되는 편은 아닙니다. 하나의 패턴으로 최대한 많은 파일을 찾는 것이 Globs의 주 용도이기 때문입니다.

* 기호

아마 Globs에서 가장 많이 사용되는 와일드카드는 * 기호는 일텐데요. * 기호는 길이와 상관없이 어떤 문자열과도 부합합니다. 심지어 공백까지도요. (공백은 길이가 0인 문자열이라고 생각하면 쉽습니다.) 단, 예외가 있는데 디렉토리 구분자로 사용되는 특수 기호, 즉 리눅스 계열에서는 /, 윈도우즈 계열에서는 \과는 부합하지 않습니다.

예를 들어, a*라는 패턴으로는 a, ab, abc, abc.txt, abc.mp3 등과 같이 이름이 a로 시작하는 모든 파일을 찾을 수 있습니다.

또 다른 예로, img라는 폴더 안에서 파일 이름은 abc로 동일한데 확장자만 다른 파일을 찾고 싶다면 img/abc.*라는 패턴을 사용하면 됩니다. 그러면 img/abc.jpg, img/abc.png, img/abc.gif와 같은 파일들이 검색될 것입니다.

** 기호

다음으로 Globs의 꽃이라고도 볼 수 있는 ** 기호에 대해서 알아볼까요? ** 기호는 0개 이상의 하위 디렉토리와 매칭이 되는데요. 예를 들어, logs/**/error.log이라는 패턴을 통해 logs/error.log, logs/a/error.log, logs/a/b/error.log, logs/a/b/c/error.log 등의 파일을 모두 찾을 수 있습니다.

특히 **/로 시작하는 패턴은 현재 디렉토리 뿐만 아니라 하위 디렉토리에 있는 파일까지 모두 재귀적으로 탐색할 수 있어서 매우 많이 쓰이는데요. 예를 들어, 현재 디렉토리 하위에 존재하는 모든 CSS 파일을 찾고 싶다면 **/*.css라는 패턴을 사용하면 됩니다. 반면에 *.css 패턴은 현재 디렉토리에 있는 CSS 파일만 찾고, 하위 디렉토리까지는 뒤지지 않습니다.

참고로 편의를 위해서 일부 설정 파일이나 개발 도구에서는 패턴 맨 앞의 **/ 기호를 생략해도 무방한 경우가 있는데요. 아무래도 파일을 검색할 때, 현재 디렉토리만 검색하기 보다는 하위에 있는 모든 디렉토리를 검색하고 싶은 경우가 많이 때문일 것입니다.

{} 괄호

리눅스에서는 파일 이름의 대소문자를 구분하기 때문에 어떤 확장자를 가진 파일을 찾을 때 소문자로 한 번 찾고 대문자로 한 번 더 찾아야하는 일이 발생하는데요. 예를 들어, 현재 디렉토리 내에 파일 이름이 jpg로 끝나거나, JPG로 끝나는 파일을 검색하고 싶을 때는 어떻게 할까요?

지금까지 배운 와일드카드를 활용해보면 **/*.jpg 패턴과 **/*.JPG 패턴을 이용해서 두 번 검색 후에 검색 결과를 합친 후 중복되는 파일을 제거해줘야 할 것 입니다.

하지만 {} 괄호를 활용하면 **/*.{jpg,JPG} 패턴 하나로 통합을 할 수가 있습니다. 즉, {} 괄호는 동시에 여러 문자열을 매칭하는 것이 가능하게합니다.

또 다른 예로, HTML 문서의 확장자는 htmhtml이 둘 다 사용되는데요. 만약에 public 폴더에 있는 모든 HTML 파일을 검색하고 싶다면 public/**/*.{htm,html} 패턴을 사용할 수 있을 것입니다.

[] 괄호

간혹가다가 문자의 범위를 기준으로 파일 이름을 매칭하고 싶을 때가 있는데요. 이럴 때는 []괄호를 사용할 수 있습니다. 예를 들어, 이름에 모음 소문자를 포함하는 파일을 검색하고 싶다면 **/*[aeiou]*이라는 패턴을 사용할 수 있습니다.

- 기호를 두 문자 사이에 넣으면 두 문자 사이에 있는 모든 문자가 매칭에 사용됩니다. 예를 들어, 대문자로 이름이 시작하는 파일을 검색하고 싶다면 **/[A-Z]*이라는 패턴을 사용할 수 있습니다.

! 기호를 [] 괄호 맨 앞에 붙이면 그 뒤에 나오는 문자를 매칭에서 제외합니다. 예를 들어, **/[!A-Z]* 패턴은 대문자로 이름이 시작하지 않는 파일만을 검색해줍니다.

() 괄호

?, * 바로 뒤에 () 괄호를 사용하면 와일드카드 매칭 시 어느 정도 선택지를 제한해줄 수 있습니다.

예를 들어, ?(ab|cd)라는 패턴은 ab 또는 cd와 매칭되며 빈문자열과도 매칭됩니다. 반면에 *(ab|cd)라는 패턴은 ab, abab, cd, cdcd, abcd, cdab, ababcdabcd 등 다양한 문자열과 매칭될 수 있습니다.

따라서 파일 이름에서 있어도 되고 없어도 되는 부분을 매칭할 때 유용하게 사용할 수 있는데요.

예를 들어, React 프로젝트에서는 확장자가 .js.jsx인 파일이 공존하기 마련인데요. 이 두 개의 확장자를 쓰고 있는 모든 파일을 찾고 싶다면 **/*.js?(x)라는 패턴을 사용할 수 있습니다. 물론 살짝 패턴이 더 길어지지만 위에서 배운 {} 괄호를 사용해서 **/*.{js,jsx}를 사용해도 무방하겠죠?

Globs vs. Regex

많은 분들이 정규식(Regex, Regular Expression)을 Globs(Global Patterns)랑 혼동하시는데요. 이 둘은 얼핏 보면 비슷해보이지만 사실 알고 보면 문법이 미묘하게 틀려서 각별히 주의가 필요합니다. 예를 들어, * 기호는 Globs에서는 길이와 상관없이 모든 문자열과 매칭되지만, 정규식에서는 .*이라고 해줘야지 같은 효력이 발생합니다.

무엇보다 두 가지 패턴 매칭 방법은 용도가 크게 다릅니다. Globs는 파일 시스템을 검색하는데 특화되어 있는 반면에, 정규식은 좀 더 범용적으로 사용할 수 있는 매칭 방법입니다. 따라서 정규식은 Globs보다 더 강력한 문자열 매칭을 제공하며 문법도 훨씬 더 복잡합니다.

단순히 파일을 찾을 때는 Globs를 쓰시는 것이 훨씬 더 쉽고 실수할 확률도 그만큼 적을 것 입니다.

마치면서

지금까지 Globs 문법에 대해서 한 번 정리를 해보았는데 어떠셨나요? 생각보다 그렇게 많이 복잡하지는 않죠? (적어도 정규식 보다는 훨씬 간단하게 느껴지실 것입니다 😁)

자주 사용되는 Glob 패턴은 인터넷에서 검색하면 어렵지 않게 구해서 그대로 복사해서 붙여넣기할 수 있기 때문에 실무에서 직접 Glob 패턴을 짤 일을 많지 않을 수도 있습니다. 하지만 개발자로서 Glob 패턴을 일고 어떤 파일이 검색될지 스스로 파악할 수 있다면 업무에 작은 도움이 될 수 있지 않을까요?