Makefile, 내장 대괄호, 변수 확장 및 명령 대체

Makefile, 내장 대괄호, 변수 확장 및 명령 대체

DRY(반복하지 마세요) 원칙을 따르기 위해 때로는 다음을 수행해야 합니다.파일 생성. 따라서 해당 파일 어딘가에 다음과 같은 레시피가 있습니다.

shell=/bin/bash
# …
.ONESHELL:
run:
    # Create bash sub-shell «cmd» var, holding a built-in test as a string
    @cmd='[ $$(grep -iE _dev </etc/hosts | wc -l) -eq 0 ]'
    # "$$" tells make to escape the dollar sign. So echoing …
    @echo "$$cmd"
    # gives «[ $(grep -iE _dev </etc/hosts | wc -l) -eq 0 ]» as I expected
    # I need this variable to be expanded and interpreted as a real
    # built-in square bracket test, so I wrote
    @$$cmd && echo "Pass ! do more magical things …" || true

나는 기대만들다이스케이프 $기호 $$cmd$cmd가 다시 나타납니다.세게 때리다인용되지 않은 문자열을 테스트하려면 컨텍스트를 괄호 안에 넣으세요. 맞죠?
그런데 오류가 났어요/bin/bash: line 2: [: too many arguments

이 오류가 발생하는 이유를 아는 사람이 있습니까?
Bash가 내가 기대하는 브래킷 테스트를 제공하지 않는 이유는 무엇입니까?
[ $(grep -iE _dev </etc/hosts | wc -l) -eq 0 ] && echo "Pass!"

감사해요.

답변1

셸의 변수 및 명령 대체는 명령 경계가 결정되고 리디렉션(및 할당)이 구문 분석된 후에 발생합니다. 프로그램 이름 및/또는 매개변수를 변수에 넣고 바꿀 수 있지만 파이프나 리디렉션 또는 $( command )할당이나 셸 키워드(예: if및 )를 포함한 기타 대체 항목을 사용할 수 없습니다 for.

이 경우 명령을 변경하고 테스트를 반전하여 교체하여 파이프와 화장실을 제거할 수 있습니다.

cmd='grep -qi _dev /etc/hosts' # note file as argument not redirection
$$cmd || do_blah

대체된 grep 명령은 파일에서 일치하는 항목을 찾지 못하면 자동으로 실패하고, 실패하면 do_blah를 실행합니다.

일반적으로 값(프로그램 매개변수뿐만 아니라)을 대체할 때 쉘 구문을 사용하려면 이를 사용하여 값(또는 값들) 대체를 수행하거나 (필요한 경우 환경 및/또는 명령 대체에 따라) eval서브쉘을 실행해야 합니다. sh -c "$$cmd"다른 쉘)).

답변2

A는 Makefile쉘 스크립트가 아닙니다. 모든 내용을 다음과 같이 더 간단하고 깔끔하게 작성할 수 있습니다.

#!/bin/sh
set -e
grep -q -iE _dev /etc/hosts
echo pass
...

관련 정보