쉘의 "*" glob을 사용하지만 파일을 제외하고 디렉토리와 일치하지 않습니까?

쉘의 "*" glob을 사용하지만 파일을 제외하고 디렉토리와 일치하지 않습니까?

배포용 zip/tarbar를 작성하는 makefile 규칙이 있습니다. 레시피에서는 CR/LF가 올바른지 확인하고 패키징하기 전에 실행 비트가 올바른지 확인하는 등 "부가가치" 작업을 수행합니다.

프로젝트에는 많은 수의 파일이 있지만 요구 사항은 다음과 같습니다: (1) GNUmakefileneed를 제외한 모든 파일 CR/LF, (3) need만 GNUmakefile필요 LF, (3) GNUmakefileneed를 제외한 모든 파일 a-x.

레시피는 다음과 같습니다.

.PHONY: convert
convert:
    chmod a-x *[^GNUmakefile*] TestData/*.dat TestVectors/*.txt
    unix2dos --keepdate --quiet *[^GNUmakefile*] TestData/*.dat TestVectors/*.txt
    dos2unix --keepdate --quiet GNUmakefile

*IDE 특정 파일과 같이 일부 파일은 명확하지 않기 때문에 뷔페의 모든 파일을 명시적으로 나열하지 않으려고 노력하고 있습니다 . ( *[^<somefile>*]이것은 깔끔한 트릭입니다. 저는전역 일치에서 패턴 제외).

문제는 TestData일치할 TestVectors때 실행 중이므로 chmod a-x디렉터리에서 자신을 제외한다는 것입니다.

뭔가를 개선해야 하는데 어떻게 해야 할지 모르겠습니다. 쉘의 "*" glob을 사용하고 싶지만 파일을 제외하고 디렉토리와 일치하지 않습니다.

어떻게 진행해야 하나요?

답변1

filter-out이 문제는 GNU Make 와 함수를 이용하여 해결하겠습니다 wildcard. 이들로 수행할 수 없는 유일한 작업 부분은 디렉터리를 필터링하는 것입니다. 이 작업은 셸을 통해 수행되어야 합니다. 아래 코드는 테스트되지 않았으며 (a) 파일 이름에 공백이나 셸 메타 TestData/*.dat문자 가 없고 (b) TestVectors/*.txt디렉터리 검사가 필요하지 않다고 가정합니다.

NORM_TOPLEVEL := $(shell for f in $(filter-out GNUMakefile,$(wildcard *)); \
                   do [ -d "$$f" ] || printf '%s\n' "$$f"; done)
NORM_TESTDIRS := $(wildcard TestData/*.dat) $(wildcard TestVectors/*.txt)

convert:
    chmod a-x $(NORM_TOPLEVEL) $(NORM_TESTDIRS)
    unix2dos --keepdate --quiet $(NORM_TOPLEVEL) $(NORM_TESTDIRS)
    dos2unix --keepdate --quiet GNUmakefile

.PHONY: convert

답변2

glob 만 zsh유형별로 파일을 선택할 수 있으므로 GNU를 가정하면 make다음과 같은 것이 필요합니다.

SHELL = zsh
.SHELLFLAGS = -o extendedglob -c

test:
        echo ^GNUmakefile(^/)

^GNUmakefile( extendedglob) 는 GNUmakefile.is (^/)를 제외하고 적용됩니다.글로벌 예선디렉토리 외부의 모든 유형의 파일을 선택하십시오. (.)파일 형식 도 참조하세요.정기적인(디렉터리 및 fifo, 심볼릭 링크, 소켓과 같은 기타 모든 비 전통적인 유형의 파일 제외...) 이것은 당신이 찾고 있는 것과 더 비슷해 보입니다. 숨겨진( ot) 파일을 포함하려면 Dglob 한정자( )를 추가하세요 (예 : .^GNUmakefile(.D)D.gitignore

확장은 *[^GNUmakefile*], , , , , , , 또는 이외의 문자로 끝나는 숨겨지지 않은 파일 이름의 목록입니다. 따라서 (다음으로 끝나기 때문에) 제외되지만 or도 제외됩니다.GNUmakefil*GNUmakefileefoo.afile.htmlbar.exe

^GNUmakefile(.)셸을 변경하지 않고 동일한 작업을 수행하려면 유사한 루프(여기서 동일 ) 를 사용해야 합니다 .

test:
        set -- *; \
        for i do \
          [ -f "$$i" ] && \
            [ ! -L "$$i" ] && \
            [ "$$i" != GNUmakefile ] && \
            set -- "$$@" "$$i"; \
          shift; \
        done; \
        [ "$$#" -gt 0 ] && echo "$$@"

( 숨겨진 파일을 포함 set -- *하도록 대체됨 set -- .* *)

find다음 항목의 가용성을 보장할 수 없는 경우 zsh가장 좋은 방법은 쉘 글로브에 의지하는 것입니다.

test:
        find . ! -name . -prune ! -name '.*' ! -name GNUmakefile \
          -type f -exec echo {} +
        find TestData/. ! -name . -prune -name '*.dat' ! -name '.*' \
          -type f -exec echo {} +

( ! -name '.*'숨겨진 파일을 포함하기 위해 제거되었습니다).

답변3

더 고급 기준으로 필터링하려는 경우 Python을 사용하여 표현식을 쉽게 확장할 수 있습니다. Python은 거의 모든 곳에 설치됩니다. 이것은 약간 장황하지만 작동합니다.

메이크파일 예:

all:
    chmod a-x $(shell python -c "import glob; import os.path; print(' '.join([x for x in glob.glob('TestData/*.dat') + glob.glob('TestVectors/*.txt') if not (os.path.isdir(x) or x == 'GNUmakefile')]))")

관련 정보