Echo

為什麼 echo -e 在 Makefile 中表現得很奇怪?

  • April 29, 2022

我正在編寫一個 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檢測到重定向並且行為不同,但是當我只是在 shell 中手動執行它時它不會/bin/echo -e 'hello\nworld' > test.txt(這會產生helloworld在單獨的行上,正如我通常所期望的那樣)。@echo --version我什至通過添加一行來確認 Makefile 正在使用 /bin/echo 而不是內置的 shell 。

這裡發生了什麼?

的 UNIX 兼容實現echo需要在-e<space>hello<newline>world<newline>那裡輸出。

那些不符合的。許多不是,這意味著它幾乎不可能echo便攜使用,printf應該改為使用bash’s echo,在它的某些(大多數)版本中,僅當您同時啟用posixxpg_echo選項時才符合要求。這可能是echo您所期望的行為。

echoGNU 附帶的獨立實用程序也是如此,該實用程序只有在其環境中coreutils使用 set 呼叫時才符合要求$POSIXLY_CORRECT(並且是足夠新的版本)。

make通常執行sh以解釋每個操作行上的命令行。

make但是,作為優化,如果程式碼足夠簡單並且它認為不需要呼叫 shell 來解釋它,則 GNU 實現可以直接執行命令。

這就解釋了為什麼echo --version給你/bin/echo,但echo ... > file需要一個 shell 來執行重定向。

您可以使用strace -fe execve make查看make執行的內容(或truss/ tusc… 如果不是 Linux,則在您的系統上等效)。

在這裡,似乎雖然您/bin/echo不合規,但您shecho內置函式是合規的。

在這裡,printf如果要擴展echo-style 轉義序列,請使用:

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

在其格式參數中,理解 C 風格的轉義序列( (echo) 與(C) 八進制序列printf的 echo 風格的轉義序列有所不同)\0xxx``\xxx

printf 'hello\nworld\n'

在這裡,您還可以這樣做:

printf '%s\n' hello world

這是在單獨的行上輸出多個參數的常見且可移植的方式。

另一種方法是添加:

SHELL = bash

Makefile供您make呼叫bash(假設它已安裝並在 中找到$PATH)而不是sh解釋命令行。或呼叫makeas make <target> SHELL=bash

這並不一定會讓它更便攜,因為現在有越來越多的系統bash預設安裝,有一些(比如在 Solaris 上)bash是建構的,因此它的echo內置預設行為是標準方式。

設置為除了上面提到的禁用 GNU優化SHELL之外的任何其他值,因此使用or ,您將在兩次呼叫之間獲得一致的行為,同時仍然不必向 bash 添加依賴項。/bin/sh``make``make <target> SHELL=sh``make <target> SHELL=/bin//sh

引用自:https://unix.stackexchange.com/questions/700675