메이크 파일의 여러 줄 bash 명령


120

몇 줄의 bash 명령을 통해 프로젝트를 컴파일하는 매우 편안한 방법이 있습니다. 하지만 이제는 makefile을 통해 컴파일해야합니다. 모든 명령이 자체 셸에서 실행된다는 것을 고려할 때 내 질문은 makefile에서 서로 의존하는 여러 줄 bash 명령을 실행하는 가장 좋은 방법무엇입니까? 예를 들면 다음과 같습니다.

for i in `find`
do
    all="$all $i"
done
gcc $all

또한 누군가가 한 줄 명령조차도 bash -c 'a=3; echo $a > file'터미널에서 올바르게 작동하지만 메이크 파일의 경우 빈 파일을 만드는 이유를 설명 할 수 있습니까?


4
두 번째 부분은 별도의 질문이어야합니다. 다른 질문을 추가하면 소음이 발생합니다.
l0b0

답변:


136

줄 연속에 백 슬래시를 사용할 수 있습니다. 그러나 쉘은 한 줄로 연결된 전체 명령을 수신하므로 세미콜론으로 일부 줄을 종료해야합니다.

foo:
    for i in `find`;     \
    do                   \
        all="$$all $$i"; \
    done;                \
    gcc $$all

그러나 find호출에서 반환 된 전체 목록을 가져 와서에 전달하려는 경우 gcc실제로 여러 줄 명령이 필요하지는 않습니다.

foo:
    gcc `find`

또는 좀 더 셸 전통적인 $(command)접근 방식을 사용합니다 ( $이스케이프에 주의하십시오 ).

foo:
    gcc $$(find)

2
여러 줄의 경우 다른 주석에 표시된대로 여전히 달러 기호를 이스케이프해야합니다.
tripleee

1
예, 짧은 답변 1. $ : = $$ 2. \ BTW로 여러 줄 추가 bash 사람은 일반적으로`find` 호출을 $$ (find)로 바꾸는 것이 좋습니다
Yauhen Yakimovich 2013-08-17

89

질문에서 알 수 있듯이 모든 하위 명령은 자체 쉘에서 실행됩니다 . 이것은 사소하지 않은 쉘 스크립트를 작성하는 것을 약간 지저분 하게 만듭니다.하지만 가능합니다! 해결책은 make가 단일 하위 명령 (단일 행)을 고려하는 것으로 스크립트를 통합하는 것입니다.

메이크 파일 내에서 쉘 스크립트 작성을위한 팁 :

  1. 다음 $으로 대체 하여 스크립트의 사용 을 피하십시오.$$
  2. ;명령 사이 에 삽입하여 스크립트를 한 줄로 작동하도록 변환
  3. 여러 줄에 스크립트를 작성하려면 다음을 사용하여 줄 끝을 이스케이프하십시오. \
  4. 선택적 set -e으로 하위 명령 실패시 중단하도록 make의 프로비저닝과 일치하도록 시작
  5. 이것은 전적으로 선택 사항이지만 스크립트를 대괄호 로 묶 ()거나 {}여러 줄 시퀀스의 응집성을 강조 할 수 있습니다. 이는 일반적인 메이크 파일 명령 시퀀스가 ​​아닙니다.

다음은 OP에서 영감을 얻은 예입니다.

mytarget:
    { \
    set -e ;\
    msg="header:" ;\
    for i in $$(seq 1 3) ; do msg="$$msg pre_$${i}_post" ; done ;\
    msg="$$msg :footer" ;\
    echo msg=$$msg ;\
    }

4
SHELL := /bin/bashmakefile에서 프로세스 대체 와 같은 BASH 관련 기능을 활성화 할 수도 있습니다 .
브렌트 브래드 번

8
미묘한 점 : 뒤에 공백 은 알려지지 않은 명령으로 {해석되는 것을 방지하는 데 중요합니다 {set.
Brent Bradburn 2015 년

3
미묘한 점 # 2 : 아마 중요하지 않습니다 메이크에서, 그러나와 포장의 구분 {}과는 ()가끔 스크립트를 복사 프롬프트 쉘에서 직접 실행하려면 큰 차이가 있습니다. 변수를 선언하고 특히 .NET set내부에서를 사용 하여 상태를 수정하여 셸 인스턴스에 혼란을 일으킬 수 있습니다 {}. ()스크립트가 환경을 수정하지 못하도록 방지합니다. 예 ( 쉘 세션이 종료 됨 ) : { set -e ; } ; false.
Brent Bradburn

다음 형식을 사용하여 주석을 포함 할 수 있습니다. command ; ## my comment \` (the comment is between ;`및`\`). 명령을 수동으로 (복사하여 붙여 넣기로) 실행 하는 경우 명령 내역에 명령을 중단하는 방식으로 주석이 포함 된다는 점을 제외 하면 잘 작동하는 것 같습니다 (다시 사용하려는 경우). [참고 : 백틱 내부에 백 슬래시를 사용하기 때문에이 주석에 대한 구문 강조 표시가 깨졌습니다.]
Brent Bradburn

makefile 내의 bash / perl / script에서 문자열을 나누려면 문자열 따옴표, 백 슬래시, 개행, (들여 쓰기 없음) 열린 문자열 따옴표를 닫습니다. 예; perl -e QUOTE print 1; QUOTE BACKSLASH NEWLINE QUOTE print 2 QUOTE
mosh

2

명령을 호출하는 데있어 문제점은 무엇입니까?

foo:
       echo line1
       echo line2
       ....

그리고 두 번째 질문에 대해, 당신은 탈출 할 필요가 $사용하여 $$즉, 대신 bash -c '... echo $$a ...'.

편집 : 다음과 같이 한 줄 스크립트로 예제를 다시 작성할 수 있습니다.

gcc $(for i in `find`; do echo $i; done)

5
원인 "모든 명령은 자체 쉘에서 실행됩니다", 반면에 command2에서 command1의 결과를 사용해야합니다. 예 에서처럼.
Jofsey

셸 호출간에 정보를 전파해야하는 경우 임시 파일과 같은 외부 저장소 형식을 사용해야합니다. 그러나 항상 동일한 셸에서 여러 명령을 실행하도록 코드를 다시 작성할 수 있습니다.
JesperE 2010

+1, 특히 단순화 된 버전의 경우. 그리고``gcc`find''`를하는 것과 같지 않습니까?
Eldar Abusalimov 2012

1
네, 그렇습니다. 그러나 물론 단순히 '에코'보다 더 복잡한 일을 할 수 있습니다.
JesperE

2

물론 Makefile을 작성하는 올바른 방법은 실제로 어떤 타겟이 어떤 소스에 의존하는지 문서화하는 것입니다. 사소한 경우에는 제안 된 솔루션이 foo자체적으로 의존 하게 되지만 물론make 순환 의존성을 떨어 뜨릴만큼 똑똑합니다. 그러나 디렉토리에 임시 파일을 추가하면 "마법처럼"종속성 체인의 일부가됩니다. 아마도 스크립트를 통해 명시적인 종속성 목록을 한 번에 생성하는 것이 좋습니다.

GNU make는 및 파일 gcc세트에서 실행 파일을 생성하기 위해 실행하는 방법을 알고 있으므로 실제로 필요한 모든 것은.c.h

foo: $(wildcard *.h) $(wildcard *.c)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.