Makefile에서 echo -e가 이상하게 동작하는 이유는 무엇입니까?

Makefile에서 echo -e가 이상하게 동작하는 이유는 무엇입니까?

저는 Makefile(해당하는 경우 Ubuntu 20.04에서)을 작성 중이며 다음 echo과 같은 간단한 Makefile을 예로 들어 보겠습니다.

test.txt:
        @echo -e 'hello\nworld'
        @echo -e 'hello\nworld' > test.txt

를 실행하면 makestdout에서도 test.txt와 동일한 내용이 표시될 것으로 예상하지만 실제로는 그렇지 않습니다. 표준 출력에서 ​​이것을 얻습니다.

hello
world

그러나 이것은 test.txt에 있습니다.

-e hello
world

한편 -eMakefile에서 다음 두 줄을 제거하면 표준 출력이 표시됩니다.

hello\nworld

test.txt에서:

hello
world

이로 인해 리디렉션이 감지되어 다른 동작을 보이는지 궁금합니다 echo. 하지만 쉘에서 수동으로 실행할 때는 그렇지 않습니다 /bin/echo -e 'hello\nworld' > test.txt(보통 예상대로 별도의 줄에 합계가 생성됩니다 hello). world나는 행을 추가하여 Makefile이 내장 쉘이 아닌 /bin/echo를 사용하고 있음을 확인했습니다 @echo --version.

여기서 무슨 일이 일어나고 있는 걸까요?

답변1

echo거기에서 출력 하려면 UNIX 호환 구현이 필요합니다 -e<space>hello<newline>world<newline>.

요건을 충족하지 못하는 분은 자격이 없습니다. 많은 경우 그렇지 않습니다. 즉, 휴대용을 사용하는 것이 거의 불가능하다는 의미입니다 echo.printf사용해야한다. 의 일부(대부분) 버전에서는 및 옵션을 모두 활성화한 경우에만 호환 bash됩니다 . 이는 아마도 예상한 동작일 것입니다.echoposixxpg_echoecho

echoGNU와 함께 제공되는 독립 실행형 유틸리티도 마찬가지입니다. 이는 coreutils해당 환경에서 set을 사용하여 호출하는 경우 $POSIXLY_CORRECT에만 호환되며 충분히 새로운 버전입니다 .

make일반적으로 sh각 작업 줄의 명령줄을 해석하기 위해 실행합니다.

make그러나 최적화로서 GNU 구현은 코드가 충분히 단순하고 이를 해석하기 위해 쉘을 호출할 필요가 없다고 생각하는 경우 명령을 직접 실행할 수 있습니다.

이는 echo --version주어진 이유를 설명 /bin/echo하지만 echo ... > file리디렉션을 수행하려면 쉘이 필요합니다.

strace -fe execve make다음을 사용하여 실행된 내용을 확인할 수 있습니다 ( makeLinux가 아닌 경우 시스템에서 truss/... 해당 항목을 사용).tusc

여기서는 /bin/echo호환되지 않지만 sh내장되어 echo있습니다.

printfecho확장된 스타일의 이스케이프 시퀀스를 원하면 여기에서 사용하세요:

printf '%b\n' 'hello\nworld'

그 안에체재매개변수, C 스타일 이스케이프 시퀀스 이해( printf(echo) 및 (C) 8진수 시퀀스에 대한 에코 스타일 이스케이프 시퀀스와 구별됨)\0xxx\xxx

printf 'hello\nworld\n'

여기서도 다음을 수행할 수 있습니다.

printf '%s\n' hello world

이는 여러 매개변수를 별도의 라인에 출력하는 일반적이고 이식 가능한 방법입니다.

또 다른 방법은 다음을 추가하는 것입니다.

SHELL = bash

명령줄을 해석하는 대신 Makefilefor make호출 bash(설치되어 있고 에 있다고 가정 ) 을 사용합니다 . 또는 로 전화하세요 .$PATHshmakemake <target> SHELL=bash

bash점점 더 많은 시스템이 기본적으로 설치되어 있기 때문에 이것이 반드시 더 이식성이 높아지는 것은 아니지만 일부 시스템(예: Solaris) 은 기본적으로 표준 방식으로 실행 bash되도록 구축되었습니다 .echo

SHELL다른 것으로 설정하면 /bin/sh위에서 언급한 GNU 최적화를 비활성화하는 부작용이 있으므로 또는 를 사용하면 bash에 대한 종속성을 추가하지 않고도 호출 간에 일관된 동작을 얻을 수 있습니다.makemake <target> SHELL=shmake <target> SHELL=/bin//sh

관련 정보