Makefile에 파일이 있는지 확인하여 삭제할 수있는 방법은 무엇입니까?


135

내 깨끗한 섹션에서 Makefile영구적으로 삭제하기 전에 파일이 있는지 확인하려고합니다. 이 코드를 사용하지만 오류가 발생합니다.

무슨 일이야?

 if [ -a myApp ]
 then
     rm myApp
 fi

이 오류 메시지가 나타납니다

 if [ -a myApp ]
 /bin/sh: Syntax error: end of file unexpected (expecting "then")
 make: *** [clean] Error 2

myApp가 변수 또는 실제 파일 이름입니까?
BugFinder

myApp은 myApplication, 즉 빌드 프로세스에 의한 파일 이름입니다.
Abruzzo Forte e Gentile

5
파일이 존재하지 않는 경우 중지하지 않으 rm -rf myApp려면 대안이 될 수 있습니다. 또는 명령 앞에 대시 ( -rm myApp)를 붙여서 rm의 오류를 무시하십시오 (그러나 추한 메시지를 인쇄합니다).
thomasa88

1
문제는 make가 규칙의 각 줄을 별도의 명령으로 취급하고 개별적으로 셸에 보내는 것입니다. `if [-a myApp] '만으로 실행하는 것과 같습니다. 이 오류가 발생하면 라인을 하나로 결합하거나 (사용하여) 또는 서로 독립적으로 각 라인으로 끝나는 솔루션이 필요합니다. 아래에 몇 가지가 있습니다.
Michael

답변:


40

그러나 두 번째 상위 답변은을 언급 ifeq하지만 이것들은 대상의 이름과 같은 수준에 있어야한다고 언급하지 않습니다. 예를 들어 파일이 존재하지 않는 경우에만 파일을 다운로드하는 경우 다음 코드를 사용할 수 있습니다.

download:
ifeq (,$(wildcard ./glob.c))
    curl … -o glob.c
endif

# THIS DOES NOT WORK!
download:
    ifeq (,$(wildcard ./glob.c))
        curl … -o glob.c
    endif


3
이 답변은 조금 이상합니다. 파일 검사는 makefile이 처리 될 때 발생하지만 나중에 make가 대상을 빌드 할 때 수행됩니다. 그 동안 파일을 삭제하면 파일이 생성되지 않습니다. 더 명확하게하기 위해 편집을했습니다.
Michael

고맙습니다! 이 점은 매뉴얼을 읽는 것이 분명하지 않았습니다.
Kevin Buchs

207

많은 사람들이 이것을 위해 쉘 스크립팅을 사용하는 것을 보는 것은 이상합니다. 기본 makefile 구문을 사용하는 방법을 찾고 있었는데, 대상 외부에서 이것을 작성하기 때문입니다. 이 wildcard기능을 사용하여 파일이 존재하는지 확인할 수 있습니다.

 ifeq ($(UNAME),Darwin)
     SHELL := /opt/local/bin/bash
     OS_X  := true
 else ifneq (,$(wildcard /etc/redhat-release))
     OS_RHEL := true
 else
     OS_DEB  := true
     SHELL := /bin/bash
 endif 

최신 정보:

나는 정말로 나를 위해 일하는 방법을 찾았다.

ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif

4
이것을 시도했지만, 나는 단지 계속 받고있다Makefile:133: *** unterminated call to function `wildcard': missing `)'. Stop.
Ant6n

1
와일드 카드를 많이 사용하므로 makefile 자체로 수행 할 수 있습니다. 깔끔한 :)
anoop

3
$(wildcard pattern)실제로 무엇을하는지 이해하는 데 도움 이됩니다. 링크를 참조하십시오 .
Dr. Dan

1
더 간결한 :FILE_EXISTS := $(or $(and $(wildcard $(PATH_TO_FILE)),1),0)
cmaster-복원 모니카

2
cygwin에서 Windows에서 실행중인 경우이 방법으로 와일드 카드를 사용하면 파일 이름에서 대소 문자 구분이 일치하므로 파일이 있지만 경로가 아닌 경로와 다른 경우에는 파일을 찾을 수 없습니다. makefile 내에서이 동작을 재정의하는 방법이없는 것 같습니다.
로저 샌더스

59

문제는 명령을 여러 줄로 나눌 때입니다. 따라서 \위와 같이 계속해서 줄 끝에서 를 사용 하거나 &&bash 의 연산자를 사용하여 한 줄로 모든 것을 얻을 수 있습니다 .

그런 다음 test명령을 사용 하여 파일이 존재하는지 테스트 할 수 있습니다 ( 예 :

test -f myApp && echo File does exist

-f file 파일이 존재하고 일반 파일 인 경우 참입니다.

-s file 파일이 존재하고 크기가 0보다 크면 True입니다.

또는하지 않습니다 :

test -f myApp || echo File does not exist
test ! -f myApp && echo File does not exist

test에 해당 [명령을 실행합니다.

[ -f myApp ] && rm myApp   # remove myApp if it exists

원래 예제에서와 같이 작동합니다.

help [또는 help test추가 구문을 참조하십시오 .


4
나는 upvoted했을 것입니다,하지만 당신은 -s특별한 경우를 경고하지 않았습니다 exists and has a size greater than zero. 작성된 질문은 크기에 구애받지 않으므로 test -e파일이나 -d디렉토리를 사용하여 존재 여부를 확인해야합니다 . 빈 파일은 (더 나은 용어를 원할 경우) 지표 / 센티넬로 특히 유용 할 수 있습니다 make.
underscore_d

제안 해 주셔서 감사합니다. -f더 일반적으로 사용되므로 기본적으로 변경 됩니다.
kenorb

testWindows를 어떻게 이용할 수 있습니까?
thowa

3
이것이 작동하려면 || true파일이 존재하지 않을 때 명령이 true를 반환하도록 끝에 추가해야 합니다.
jcubic

2
@AndrewMackenzie에서을 확인하십시오 test -f myApp || CMD. 실패 할 ||경우 -f– 존재하지 않는 경우 ( ||) 명령을 실행하십시오. 말이 되나요?
kenorb

50

계속하려면 줄 끝에 백 슬래시가 필요할 수 있습니다 (아마도 make 버전에 따라 다름).

if [ -a myApp ] ; \
then \
     rm myApp ; \
fi;

2
Makefile 구문이 아닌 것 같습니다. sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/…
holms

@holms는 bash 구문입니다. 새로운 줄을 빠져 나가면 하나의 bash 명령으로 처리 할 수 ​​있습니다. 기본적 make으로 새 줄에는 새로운 bash 명령이 있습니다. \ 줄 끝에 많은 것을 갖는 성가신 것을 제외하고 이것의 주요 경고는 모든 명령 ;이 bash에 내재되어있는 것으로 종료되어야한다는 것입니다.
flungo

1
정답은 @holms입니다. '\'나 와일드 카드는이 목적을위한 것이 아닙니다. 와일드 카드를 사용하는 이유는 코드를 명확하게하기위한 것입니다. 이 메소드는 읽기 쉽지 않을뿐만 아니라 구문 오류가 발생하기 쉽습니다.
Maitreya

1
제공된 @holms 링크가 더 이상 작동하지 않습니다. 대신 gnu.org/software/make/manual/make.html#Conditionals를 사용하십시오
fero

이것은 원래의 질문자가했던 것과 틀린 것을 일치시키기 때문에 훌륭한 대답입니다 .Makefile이 시작될 때가 아니라 대상이 빌드 될 때 파일이 존재하는지 여부에 따라 작동합니다. 대부분의 사람들이 기대하는 것입니다. 대부분의 시간을 원합니다. 몇 가지 이상한 경우 @cnst의 대답이 더 좋습니다.
Michael

31

또는 원하는대로 한 줄에 넣으 make십시오.

if [ -a myApp ]; then rm myApp; fi;

\이 경우 좋은 대답 (그리고 upvotes을 얻어야한다)하는 경우에 단지 사용하도록 전환하지만, 너무 잘하는 작업이 더 복잡 인 경우에 작동하지 않습니다
마이클

[-a myApp] && rm myApp
Robin Hsu

14

세미콜론 누락

if [ -a myApp ];
then
  rm myApp
fi

그러나 오류 메시지를 방지하기 위해 삭제하기 전에 존재 여부를 확인한다고 가정합니다. 그렇다면 rm -f myApp어떤 "강제"삭제를 사용할 수 있습니다 . 즉 파일이 존재하지 않으면 오류가 발생하지 않습니다.


1
ThHat은 내가하고 싶은 일입니다. 고마워
Abruzzo Forte e Gentile

1
if가 여전히 여러 줄로 분산되어 있기 때문에 Makefile에서는 작동하지 않습니다. 한 줄에 넣거나 \ es를 사용해야합니다. \ es를 추가하더라도 일부 세미콜론이 여전히 누락되었습니다.
Michael

13
FILE1 = /usr/bin/perl
FILE2 = /nofile

ifeq ($(shell test -e $(FILE1) && echo -n yes),yes)
    RESULT1=$(FILE1) exists.
else
    RESULT1=$(FILE1) does not exist.
endif

ifeq ($(shell test -e $(FILE2) && echo -n yes),yes)
    RESULT2=$(FILE2) exists.
else
    RESULT2=$(FILE2) does not exist.
endif

all:
    @echo $(RESULT1)
    @echo $(RESULT2)

실행 결과 :

bash> make
/usr/bin/perl exists.
/nofile does not exist.

이것은 OP가 makefile에 대해 묻는 것을 놓친 것 같습니다. 왜 "&& echo -n yes"가 필요한지 이해하지 못했습니다. 설명 : test -e가 1 (찾을 수 없음)을 반환하면 쉘은 echo 명령을 실행하지 않으므로 ifeq의 yes와 일치하지 않습니다
Brad Dre

나는 당신이 당신의 설명문에서 그것을 올바르게 이해한다고 생각합니다.
Robin Hsu

@BradDre- NL이없는 문자열 echo -n yes의 성공을 변경합니다 . 는 다음 코드 하드와 비교 할 수 있습니다 . 쉘 명령의 성공 상태가 아니라 비교할 문자열을 원 하기 때문 입니다. testyesifeqyesifeq
Jesse Chisholm

8

한 줄 솔루션 :

   [ -f ./myfile ] && echo exists

오류 조치가있는 한 줄 솔루션 :

   [ -f ./myfile ] && echo exists || echo not exists

make clean지시문에 사용 된 예 :

clean:
    @[ -f ./myfile ] && rm myfile || true

그리고 make clean항상 오류 메시지없이 작동합니다!


3
@rm -f myfile을 수행하십시오. "-f"플래그로 인해 "rm"은 파일의 존재 여부에 관계없이 0으로 종료됩니다.
Alexey Polonsky

또는 -rm myfile리드 대시가 오류를 무시하도록 지시합니다.
Jesse Chisholm

1
제 경우에는 || <오류 조치>에 문제가 발생했습니다. 파일이 존재하지 않으면 true를 반환 한 마지막 예제에서이 문제를 해결했습니다. 감사합니다!
Flic

나에게 myfile의 경로는 아포스트로피 ( ')가 있어야한다 :@[ -f 'myfile' ] && rm myfile
Sten

0
test ! -f README.md || echo 'Support OpenSource!' >> README.md

"README.md가 존재하지 않으면 아무 것도하지 않고 종료합니다. 그렇지 않으면 끝에 텍스트를 추가하십시오."

&&대신 사용 ||하면 파일이 없을 때 오류가 발생합니다.

Makefile:42: recipe for target 'dostuff' failed
make: *** [dostuff] Error 1

0

난 노력했다:

[ -f $(PROGRAM) ] && cp -f $(PROGRAM) $(INSTALLDIR)

그리고 긍정적 인 경우는 효과가 있었지만 우분투 bash 쉘은 이것을 TRUE라고 부르고 사본을 끊습니다.

[ -f  ] && cp -f  /home/user/proto/../bin/
cp: missing destination file operand after '/home/user/proto/../bin/'

이 오류가 발생하면 파일에 make 파일이 있는지 확인하는 방법을 Google에 알려 드리겠습니다.


0
ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif

위에 게시 된이 솔루션이 가장 효과적입니다. 그러나 PATH_TO_FILE 할당을 문자열 화하지 않도록하십시오 (예 :

PATH_TO_FILE = "/usr/local/lib/libhl++.a" # WILL NOT WORK

반드시 있어야합니다

PATH_TO_FILE = /usr/local/lib/libhl++.a

-2

줄을 계속하기 위해 \를 사용하는 @ mark-wilkins의 답변과 같은 대답; 쉘에서 또는 @kenorb에서 이것을 한 줄로 변경하는 것이 좋으며이 문제를 해결할 것입니다.

@ alexey-polonsky가 지적했듯이 원래 문제에 대한 더 간단한 대답이 있습니다. -f 플래그를 사용하여 오류가 발생하지 않도록 rm

rm -f myApp

더 간단하고 빠르며 안정적입니다. 슬래시와 빈 변수로 끝나지 않도록 조심하십시오.

rm -f / $ (myAppPath) #이 작업을 수행하지 마십시오

시스템이 삭제 될 수 있습니다.


1
이것은 OP가 가지고있는 파일을 삭제하는 좋은 대답이지만이 질문을 찾는 대부분의 사람들이 실제로 파일을 삭제하지 않을 것이라고 확신합니다. 이것은 실제로 대부분의 답변이 전혀 언급하지 않는다는 사실에 의해 입증됩니다 rm. BTW, 나는 디렉토리 rm -f /$(myAppPath)이기 때문에 손상을 입지 않을 것이라고 확신합니다 . /-r
cnst

이것은 더 간단한 해결책이 아닙니다. @cnst가 말했듯이 원래 포스터가 단순히을하고 싶지 않은 이유가있을 수 있습니다 ( rm -f예 : rm변수를 원할 수 있음) .
Dan Nguyen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.