glob — 패턴에 맞는 파일 이름 찾기

glob — 패턴에 맞는 파일 이름 찾기

쉘에서 *.tcl 같은 와일드카드로 파일 목록을 얻는 것처럼, Tcl 스크립트에서도 같은 방식으로 파일 이름을 찾고 싶을 때가 있어요. 그때 쓰는 명령어가 glob이에요.

출처: Tcl Built-In Commands — glob

본문

시그니처

glob ?switches? ?pattern ...?

glob은 csh 셸이나 bash 셸과 비슷하게 파일 이름 글러빙을 수행해요. pattern 인자 중 어느 하나라도 매칭되는 이름을 가진 파일들의 리스트를 반환해요. 리스트의 순서는 보장되지 않으니 정렬이 필요하면 lsort를 쓰세요.

옵션

glob 앞쪽 인자가 -로 시작하면 스위치로 취급돼요. 지원되는 스위치는 다음과 같아요.

  • -directory directory — 주어진 디렉토리에서 시작해 패턴과 매칭되는 파일을 찾아요. glob에 민감한 문자를 포함한 디렉토리 이름을 따로 이스케이프하지 않고도 검색할 수 있게 해줘요. -path와 함께 쓸 수 없어요.
  • -join — 옵션 처리 후 남은 패턴 인자들을 디렉토리 구분자로 이어 붙인 하나의 패턴으로 취급해요.
  • -nocomplain — 결과가 빈 목록이어도 오류 없이 반환되게 해요. 이 스위치가 없으면 결과가 비어 있을 때 오류가 나요.
  • -path pathPrefix — 주어진 pathPrefix로 시작하고 나머지 이름이 패턴과 매칭되는 파일을 찾아요. glob에 민감한 문자를 포함한 비슷한 이름의 파일들을 찾을 때 유용해요. -directory와 함께 쓸 수 없어요. 예를 들어 $path와 루트 이름이 같지만 확장자가 다른 모든 파일을 찾으려면 glob -path [file rootname $path] .*를 쓰면 $path에 glob 민감 문자가 많아도 잘 동작해요.
  • -tails — 어떤 -directory-path 지정에서 마지막으로 이름 붙은 디렉토리 다음에 오는 부분만 반환해요. glob -tails -directory $dir *set pwd [pwd]; cd $dir; glob *; cd $pwd와 같아요. -path 지정에서는 반환된 이름이 마지막 경로 세그먼트를 포함해서, glob -tails -path [file rootname ~/foo.tex] .*foo.aux foo.bib foo.tex 같은 경로를 반환해요.
  • -types typeListtypeList와 매칭되는 파일이나 디렉토리만 나열해요. 목록 항목은 두 가지 형태가 있어요.
    • 첫 번째 형태는 Unix find-type 옵션과 같아요: b(블록 특수 파일), c(문자 특수 파일), d(디렉토리), f(일반 파일), l(심볼릭 링크), p(네임드 파이프), s(소켓). 여러 타입을 지정할 수 있고, 주어진 타입 중 하나라도 매칭되는 파일을 모두 반환해요. 심볼릭 링크는 -types l을 주거나 링크의 대상이 요청 타입과 매칭될 때 모두 반환돼요(그래서 디렉토리로 가는 링크는 -types d에서도 반환돼요).
    • 두 번째 형태는 주어진 타입이 전부 매칭되어야 해요: 파일 권한으로 r, w, x와 특별 권한 경우인 readonly, hidden이에요. Macintosh에서는 macOS 타입·크리에이터도 지원해요(네 글자 항목은 macOS 타입, 예: TEXT). {macintosh type XXXX}{macintosh creator XXXX} 형태는 각각 타입·크리에이터와 매칭돼요. 인식 못 하는 타입이나 여러 macOS 타입·크리에이터를 지정하면 오류가 나요.
    • 두 형태는 섞을 수 있어요. -types {d f r w}는 읽기 그리고 쓰기 권한이 둘 다 있는 일반 파일 또는 디렉토리를 모두 찾아요. 다음 둘은 동등해요:
      glob -type d *
      glob */
      
      단, 첫 번째는 끝의 /를 반환하지 않고 더 플랫폼 독립적이에요.
  • -- — 스위치의 끝을 표시해요. 그다음 인자는 -로 시작해도 패턴으로 취급돼요.

글러빙 패턴

pattern 인자에는 string match가 지원하는 것의 상위 집합인 다음 특수 문자가 들어갈 수 있어요.

패턴 의미
? 임의의 한 문자
* 0개 이상의 연속된 문자
[chars] chars 중 한 문자 (범위 a-b 가능)
\x 문자 x 자체
{a,b,...} a, b 등 하위 패턴 중 어느 하나

Unix에서는 csh처럼 파일 이름 시작 또는 / 바로 뒤의 .이 숨김을 뜻하므로 명시적으로({} 포함) 매칭해야 해요(-types hidden을 주면 예외). 다른 플랫폼에서는 .로 시작하는 파일을 일반 파일과 동일하게 다루되, 특별한 디렉토리 ...만 명시적으로 매칭해야 해요(재귀 패턴이 디렉토리 계층을 위로도 올라가지 않게 하려는 것). 또 모든 / 문자는 명시적으로 매칭해야 해요.

패턴의 첫 문자가 ~이면 그 뒤에 오는 사용자 이름의 홈 디렉토리를 가리켜요. ~ 바로 뒤에 /가 오면 HOME 환경 변수의 값이 사용돼요.

glob은 csh 글러빙과 두 가지 점에서 달라요. 하나는 결과를 정렬하지 않는다는 점(lsort로 정렬), 다른 하나는 실제로 존재하는 파일만 이름을 반환한다는 점이에요(csh는 ?, *, []가 없는 패턴이면 존재 여부를 확인하지 않아요).

glob이 틸드 ~로 시작하는 상대 경로를 반환할 때(예: glob *이나 glob -tails), 반환 리스트는 틸드를 ./로 인용하지 않아요. 그래서 그 이름을 나중에 file join으로 쓸 때 사용자의 홈 디렉토리를 가리키는 절대 경로로 해석되지 않도록 주의해야 해요.

Windows 이식성 문제

Windows UNC 이름에서는 경로의 서버명·공유명 구성 요소에 ?, *, []를 쓸 수 없어요. Windows NT에서 ~username@domain 형태의 패턴은 지정된 NT 도메인 서버의 계정 정보를 가진 사용자의 홈 디렉토리를 가리키고, 그 외에는 로컬 컴퓨터에서 계정 정보를 가져와요.

백슬래시는 glob에 특별한 의미가 있으므로 Windows 스타일 경로 구분자를 포함한 패턴은 주의가 필요해요. C:\\foo\\*C:\foo\*로 해석되는데, 여기서 \f는 문자 f 하나와 매칭되고 \*는 문자 * 하나와 매칭돼(와일드카드가 아님)요. 해결책은 Unix 스타일 슬래시를 경로 구분자로 쓰는 거예요. Windows 스타일 경로는 file join $pathfile normalize $path로 Unix 스타일로 변환할 수 있어요.

예제

현재 디렉토리의 모든 Tcl 파일 찾기:

glob *.tcl

현재 디렉토리가 어디든 사용자 홈 디렉토리의 Tcl 파일 찾기:

glob -directory ~ *.tcl

현재 디렉토리의 모든 하위 디렉토리 찾기:

glob -type d *

이름에 a, b, 또는 연속 cde를 포함하는 모든 파일 찾기:

glob -type f *{a,b,cde}*

더 알아보기