저는 Makefile(해당하는 경우 Ubuntu 20.04에서)을 작성 중이며 다음 echo
과 같은 간단한 Makefile을 예로 들어 보겠습니다.
test.txt:
@echo -e 'hello\nworld'
@echo -e 'hello\nworld' > test.txt
를 실행하면 make
stdout에서도 test.txt와 동일한 내용이 표시될 것으로 예상하지만 실제로는 그렇지 않습니다. 표준 출력에서 이것을 얻습니다.
hello
world
그러나 이것은 test.txt에 있습니다.
-e hello
world
한편 -e
Makefile에서 다음 두 줄을 제거하면 표준 출력이 표시됩니다.
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
됩니다 . 이는 아마도 예상한 동작일 것입니다.echo
posix
xpg_echo
echo
echo
GNU와 함께 제공되는 독립 실행형 유틸리티도 마찬가지입니다. 이는 coreutils
해당 환경에서 set을 사용하여 호출하는 경우 $POSIXLY_CORRECT
에만 호환되며 충분히 새로운 버전입니다 .
make
일반적으로 sh
각 작업 줄의 명령줄을 해석하기 위해 실행합니다.
make
그러나 최적화로서 GNU 구현은 코드가 충분히 단순하고 이를 해석하기 위해 쉘을 호출할 필요가 없다고 생각하는 경우 명령을 직접 실행할 수 있습니다.
이는 echo --version
주어진 이유를 설명 /bin/echo
하지만 echo ... > file
리디렉션을 수행하려면 쉘이 필요합니다.
strace -fe execve make
다음을 사용하여 실행된 내용을 확인할 수 있습니다 ( make
Linux가 아닌 경우 시스템에서 truss
/... 해당 항목을 사용).tusc
여기서는 /bin/echo
호환되지 않지만 sh
내장되어 echo
있습니다.
printf
echo
확장된 스타일의 이스케이프 시퀀스를 원하면 여기에서 사용하세요:
printf '%b\n' 'hello\nworld'
그 안에체재매개변수, C 스타일 이스케이프 시퀀스 이해( printf
(echo) 및 (C) 8진수 시퀀스에 대한 에코 스타일 이스케이프 시퀀스와 구별됨)\0xxx
\xxx
printf 'hello\nworld\n'
여기서도 다음을 수행할 수 있습니다.
printf '%s\n' hello world
이는 여러 매개변수를 별도의 라인에 출력하는 일반적이고 이식 가능한 방법입니다.
또 다른 방법은 다음을 추가하는 것입니다.
SHELL = bash
명령줄을 해석하는 대신 Makefile
for make
호출 bash
(설치되어 있고 에 있다고 가정 ) 을 사용합니다 . 또는 로 전화하세요 .$PATH
sh
make
make <target> SHELL=bash
bash
점점 더 많은 시스템이 기본적으로 설치되어 있기 때문에 이것이 반드시 더 이식성이 높아지는 것은 아니지만 일부 시스템(예: Solaris) 은 기본적으로 표준 방식으로 실행 bash
되도록 구축되었습니다 .echo
SHELL
다른 것으로 설정하면 /bin/sh
위에서 언급한 GNU 최적화를 비활성화하는 부작용이 있으므로 또는 를 사용하면 bash에 대한 종속성을 추가하지 않고도 호출 간에 일관된 동작을 얻을 수 있습니다.make
make <target> SHELL=sh
make <target> SHELL=/bin//sh