[英]How to use shell commands in Makefile
我正在嘗試在其他命令(例如 echo、rsync)中使用ls
的結果:
all:
<Building, creating some .tgz files - removed for clarity>
FILES = $(shell ls)
echo $(FILES)
但我得到:
make
FILES = Makefile file1.tgz file2.tgz file3.tgz
make: FILES: No such file or directory
make: *** [all] Error 1
我試過使用echo $$FILES
、 echo ${FILES}
和echo $(FILES)
,但沒有成功。
和:
FILES = $(shell ls)
像這樣在下面縮進, all
是一個構建命令。 所以這擴展$(shell ls)
,然后嘗試運行命令FILES...
。
如果FILES
應該是make
變量,則需要在配方部分之外分配這些變量,例如:
FILES = $(shell ls)
all:
echo $(FILES)
當然,這意味着在運行任何創建 .tgz 文件的命令之前, FILES
將被設置為“從ls
輸出”。 (盡管Kaz 指出變量每次都會重新擴展,因此最終它將包含 .tgz 文件;一些 make 變體具有FILES:=...
以避免這種情況,以提高效率和/或正確性。1 )
如果FILES
應該是一個 shell 變量,你可以設置它,但你需要在 shell-ese 中進行,沒有空格,並引用:
all:
FILES="$(shell ls)"
但是,每一行都由一個單獨的 shell 運行,所以這個變量不會存活到下一行,所以你必須立即使用它:
FILES="$(shell ls)"; echo $$FILES
這有點傻,因為 shell 首先會為你擴展*
(和其他 shell glob 表達式),所以你可以:
echo *
作為您的 shell 命令。
最后,作為一般規則(並非真正適用於此示例):正如世界語在評論中指出的那樣,使用ls
中的output並不完全可靠(一些細節取決於文件名,有時甚至取決於ls
的版本;某些版本的ls
嘗試在某些情況下對 output 進行消毒)。 因此,作為l0b0和idelic注釋,如果您正在使用 GNU make,則可以使用$(wildcard)
和$(subst...)
來完成make
自身內部的所有操作(避免任何“文件名中的奇怪字符”問題)。 (在sh
腳本中,包括 makefile 的配方部分,另一種方法是使用find... -print0 | xargs -0
來避免被空格、換行符、控制字符等絆倒。)
1 GNU Make 文檔進一步指出 POSIX make 在 2012 年添加了::=
賦值。 我沒有為此找到指向 POSIX 文檔的快速參考鏈接,我也不知道哪些變體支持::=
賦值,盡管 GNU make
今天支持,與:=
具有相同的含義,即進行賦值現在隨着擴張。
請注意, VAR:= $(shell command args...)
也可以拼寫為VAR.= command args...
在幾個make
變體中,包括據我所知的所有現代 GNU 和 BSD 變體。 這些其他變體沒有$(shell)
因此使用VAR.= command args...
在更短和在更多變體中工作方面更勝一籌。
此外,除了 torek 的回答之外:突出的一件事是您正在使用延遲評估的宏分配。
如果您使用的是 GNU Make,請使用:=
賦值而不是=
。 此賦值導致右側立即展開,並存儲在左側變量中。
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...)
FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
如果使用=
賦值,則意味着$(FILES)
的每次出現都將擴展$(shell...)
語法,從而調用 shell 命令。 這將使您的 make 作業運行得更慢,甚至會產生一些令人驚訝的后果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.