2012-04-05 4 views
56

내가 다른 명령에 ls (예 : 에코, rsync를)의 결과를 사용하기 위해 노력하고있어에서 쉘 명령어를 사용하는 방법 :메이크

all: 
    <Building, creating some .tgz files - removed for clarity> 
    FILES = $(shell ls) 
    echo $(FILES) 

을하지만 수 :

make 
FILES = Makefile file1.tgz file2.tgz file3.tgz 
make: FILES: No such file or directory 
make: *** [all] Error 1 

나 ' 시도가 echo $$FILES, echo ${FILES}echo $(FILES)인데 운이 없었습니다. 와

답변

79

: 그런 all 아래에 들여 쓰기

FILES = $(shell ls) 

, 그것은 빌드 명령입니다. 따라서 이것은 $(shell ls)을 확장 한 다음 FILES ... 명령을 실행하려고 시도합니다. FILES가 "ls 출력"으로 설정한다는 것을 의미 물론

FILES = $(shell ls) 
all: 
     echo $(FILES) 

: FILESmake 변수가 될 것으로 예상되는 경우

, 이러한 변수는 예를 들면, 레시피 부 외측 할당 받아야 전에 .tgz 파일을 만드는 명령을 실행하십시오. (Kaz notes으로 변수마다 팽창 재 있지만, 그래서 결국은 .TGZ 파일이 포함됩니다 일부는 변형 효율성 및/또는 정확성,이를 방지하기 위해 FILES := ...을 가지고 있는지 확인 1합니다.)

FILES 인 경우 쉘 변수를해야하는데, 당신은 그것을 설정할 수 있지만 공백없이, 쉘 양반에 그것을 할 필요가 있고, 인용 : 그러나

all: 
     FILES="$(shell ls)" 

는, 각 라인은 별도의 쉘에 의해 실행되기 때문에이 변수가 다음 줄까지 살아남지 않으므로 즉시 사용해야합니다.

쉘 명령과

 echo * 

: 쉘이 처음에 당신을 위해 * (다른 쉘 글로브 식)를 확장하기 때문에 1,363,210

 FILES="$(shell ls)"; echo $$FILES 

이 그래서 그냥 할 수있는 모든 조금 바보입니다.

마지막으로, 일반적인 규칙 (이 예에 정말 해당되지 않음)과 같이 주석 esperanto로 노트, ls의 출력을 사용하여 완전히 신뢰할 수 없습니다 (일부 세부 사항은 때때로 파일 이름과 ls 심지어 버전에 따라 일부 경우에 따라 ls 버전의 출력물을 위생적으로 처리하려고 시도합니다). 따라서 l0b0idelic으로 GNU make를 사용하는 경우 $(wildcard)$(subst ...)을 사용하여 make 내부의 모든 것을 수행 할 수 있습니다 ("파일 이름에 이상한 문자"문제가 발생하지 않음). (메이크의 레시피 부를 포함 sh 스크립트, 또 다른 방법 등 공백, 개행 제어 문자 걸려 넘어 피할 find ... -print0 | xargs -0를 사용하고,.)


1The GNU Make documentation notes further that POSIX make added ::= assignment in 2012.나는 이것에 대한 POSIX 문서에 대한 빠른 참조 링크를 찾지 못했고 make 변종이 ::= 할당을 지원하는 것을 알지 못했지만 GNU make는 현재 :=과 동일한 의미로 즉, 지금 할당을합니다. 확장.

VAR := $(shell command args...)은 현대의 모든 GNU 및 BSD 변형을 비롯하여 여러 개의 make 변형으로 철자를 넣을 수 있습니다. 이 다른 변종에는 $(shell)이 없으므로 VAR != command args...을 사용하면 더 짧은 변종 인 이 더 우수합니다.

+0

감사합니다. 나는 정교한 명령어 ('ss'와 함께'ls')를 사용하고 rsync와 다른 명령들에서 결과를 사용하고 싶습니다. 나는 긴 명령을 반복해서 반복해야만 하는가? 내부 Make 변수에 결과를 저장할 수 없습니까? –

+1

Gnu make는 그렇게 할 수있는 방법이 있을지 모르지만 사용하지 않았고, 우리가 사용하는 모든 끔찍하게 복잡한 makefile은 쉘 변수와 거대한 한 줄짜리 쉘 명령어를 각 라인의 끝에 ";" 필요에 따라. (여기 백 슬래시 시퀀스로 작업하기위한 코드 인코딩을 얻을 수 없다, 흠) – torek

+0

또한 [ls'] (http://mywiki.wooledge.org/ParsingLs) 대신 [' 와일드 카드'는 내장되어 있습니다.] (https://www.gnu.org/software/make/manual/make.html#Wildcard-Function). – l0b0

29

torek의 답변 외에도 눈에 띄는 점은 느리게 평가 된 매크로 할당을 사용하고 있다는 것입니다.

GNU Make를 사용하는 경우 = 대신 := 할당을 사용하십시오. 이 할당은 오른 쪽이 즉시 확장되어 왼손 변수에 저장됩니다. 당신이 = 할당을 사용하는 경우

FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...) 

FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...) 

, 그것은 $(FILES)의 모든 단일 발생이 $(shell ...) 구문을 확대하고, 따라서 쉘 명령을 호출된다는 것을 의미합니다. 이것은 귀하의 직업을 더 느리게 실행하거나 심지어 놀라운 결과를 가져올 것입니다.

+0

목록이 생겼으니 이제 목록의 각 항목을 반복하고 명령을 실행하는 방법은 무엇입니까? 이러한 빌드 또는 테스트? – anon58192932

+0

@ anon58192932 명령을 실행하는 특정 반복은 일반적으로 빌드 레서피의 쉘 구문 조각에서 이루어 지므로 make에서보다 다음과 같이 쉘에서 발생합니다 :'for x in $ (FILES); 명령 $$ x; 다. 하나의'$ '를 쉘에 전달하는'$$'을 두 배로 늘렸다. 또한 셸 조각은 단 하나의 라이너입니다. 멀티 라인 쉘 코드를 작성하려면,'make' 자체에 의해 처리되고 한 줄로 접혀진 백 슬래시 연속을 사용하십시오. 이는 쉘 명령 분리 세미콜론이 필수임을 의미합니다. – Kaz