# [AIdrifter CS 浮生筆錄](https://hackmd.io/s/rypeUnYSb) <br> Makefile 字串處理常見語法
# 一般字串處理
## subst
```Shell
$(subst <from>,<to>,<text>)
```
名稱:字符串替換函數——subst。
功能:把字串`<text>`中的`<from>`字符串替換成`<to>`。
返回:函數返回被替換過後的字符串。
示例:
```Shell
$(subst ee,EE,feet on the street)
```
把「f**ee**t on the str**ee**t」中的「ee」替換成「EE」,返回結果是「f**EEt** on the str**EE**t」。
## patsubst
```Shell
$(patsubst <pattern>,<replacement>,<text>)
```
名稱:模式字符串替換函數——patsubst。
功能:查找`<text>`中的單詞(單詞以「空格」、「Tab」或「回車」「換行」分隔)是否符合模式`<pattern>`,如果匹配的話,則以`<replacement>`替換。這裡,`<pattern>`可以包括通配符「**%**」,表示任意長度的字串。如果`<replacement>`中也包含「%」,那麼,`<replacement>`中的這個「%」將是`<pattern>`中的那個「%」所代表的字串。(可以用「」來轉義,以「%」來表示真實含義的「%」字符)
返回:函數返回被替換過後的字符串。
示例:
```Shell
$(patsubst %.c,%.o,x.c.c bar.c)
```
把字串「x.c.**c** bar.**c**」符合模式[%.c]的單詞替換成[%.o],返回結果是「x.c.**o** bar.**o**」
備註:
這和我們前面「變量章節」說過的相關知識有點相似。如:
`「$(var:<pattern>=<replacement>)」`
相當於
`「$(patsubst <pattern>,<replacement>,$(var))」`,
而`「$(var: <suffix>=<replacement>)」`
則相當於
`「$(patsubst %<suffix>,%<replacement>,$(var))」`。
例如有:objects = foo.o bar.o baz.o,
那麼,`「$(objects:.o=.c)」`和`「$(patsubst %.o,%.c,$(objects))」`是一樣的。
## strip
```Shell
$(strip <string>)
```
名稱:去空格函數——strip。
功能:去掉`<string>`字串中開頭和結尾的空字符。
返回:返回被去掉空格的字符串值。
示例:
```Shell
$(strip a b c )
```
把字串「a b c 」去到**開頭**和**結尾**的空格,結果是「a b c」。
## findstring
```Shell
$(findstring <find>,<in>)
```
名稱:查找字符串函數——findstring。
功能:在字串`<in>`中查找`<find>`字串。
返回:如果找到,那麼返回`<find>`,否則返回空字符串。
示例:
```Shell
$(findstring a,a b c)
```
返回「a」字符串,
```shell
$(findstring d,a b c)
```
返回「」字符串(空字符串)
## filter
```shell
$(filter <pattern...>,<text>)
```
名稱:過濾函數——filter。
功能:以`<pattern>`模式過濾`<text>`字符串中的單詞,保留符合模式`<pattern>`的單詞。可以有多個模式。
返回:返回符合模式`<pattern>`的字串。
示例:
```Shell
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
```
`$(filter %.c %.s,$(sources))`返回的值是「foo.**c** bar.**c** baz.**s**」。
## filter-out
```Shell
$(filter-out <pattern...>,<text>)
```
名稱:反過濾函數——filter-out。
功能:以`<pattern>`模式過濾`<text>`字符串中的單詞,去除符合模式`<pattern>`的單詞。可以有多個模式。
返回:返回不符合模式`<pattern>`的字串。
示例:
```Shell
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains),$(objects))
```
返回值是「foo.o bar.o」。
## sort
```Shell
$(sort <list>)
```
名稱:排序函數——sort。
功能:給字符串`<list>`中的單詞排序(升序)。
返回:返回排序後的字符串。
示例:
`$(sort foo bar lose)`
返回「bar foo lose」 。
備註:sort函數會去掉`<list>`中相同的單詞。
## word
```Shell
$(word <n>,<text>)
```
名稱:取單詞函數——word。
功能:取字符串`<text>`中第`<n>`個單詞。(從一開始)
返回:返回字符串`<text>`中第`<n>`個單詞。如果`<n>`比`<text>`中的單詞數要大,那麼返回空字符串。
示例:$(word 2, foo **bar** baz)返回值是「**bar**」。
## wordlist
```Shell
$(wordlist <s>,<e>,<text>)
```
名稱:取單詞串函數——wordlist。
功能:從字符串`<text>`中取從`<s>`開始到<e>的單詞串。`<s>`和`<e>`是一個數字。
返回:返回字符串`<text>`中從`<s>`到`<e>`的單詞字串。如果`<s>`比`<text>`中的單詞數要大,那麼返回空字符串。如果`<e>`大於`<text>`的單詞數,那麼返回從`<s>`開始,到`<text>`結束的單詞串。
示例: $(wordlist **2**, **3**, foo bar baz)返回值是「bar baz」。
## words
```shell
$(words <text>)
```
名稱:單詞個數統計函數——words。
功能:統計`<text>`中字符串中的單詞個數。
返回:返回`<text>`中的單詞數。
示例:$(words, foo bar baz)返回值是「3」。
備註:如果我們要取`<text>`中最後的一個單詞,我們可以這樣:
```Shell
$(word $(words <text>),<text>)。
```
## firstword
```Shell
$(firstword <text>)
```
名稱:首單詞函數——firstword。
功能:取字符串`<text>`中的第一個單詞。
返回:返回字符串`<text>`的第一個單詞。
示例:$(firstword foo bar)返回值是「foo」。
備註:這個函數可以用word函數來實現:``$(word 1,<text>)``。
以上,是所有的字符串操作函數,如果搭配混合使用,可以完成比較複雜的功能。這裡,舉一個現實中應用的例子。我們知道,make使用「VPATH」變量來指定「依賴文件」的搜索路徑。於是,我們可以利用這個搜索路徑來指定編譯器對頭文件的搜索路徑參數CFLAGS,如:
```Shell
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
```
如果我們的「$(VPATH)」值是「src:../headers」,那麼「$(patsubst %,-I%,$(subst :, ,$(VPATH)))」將返回「-Isrc -I../headers」,這正是cc或gcc搜索頭文件路徑的參數。
# 文件相關字串處理
下面我們要介紹的函數主要是處理文件名的。每個函數的參數字符串都會被當做一個或是一系列的文件名來對待。
## dir
```Shell
$(dir <names...>)
```
名稱:取目錄函數——dir。
功能:從文件名序列`<names>`中取出目錄部分。目錄部分是指最後一個反斜槓(「/」)之前的部分。如果沒有反斜槓,那麼返回「./」。
返回:返回文件名序列`<names>`的目錄部分。
示例: $(dir **src**/foo.c hacks)返回值是「**src/** **./**」。
## notdir
```Shell
$(notdir <names...>)
```
名稱:取文件函數——notdir。
功能:從文件名序列`<names>`中取出非目錄部分。非目錄部分是指最後一個反斜槓(「/」)之後的部分。
返回:返回文件名序列`<names>`的非目錄部分。
示例: $(notdir src/**foo.c** hacks)返回值是「**foo.c** hacks」。
## suffix
```Shell
$(suffix <names...>)
```
名稱:取後綴函數——suffix。
功能:從文件名序列`<names>`中取出各個文件名的後綴。
返回:返回文件名序列`<names>`的後綴序列,如果文件沒有後綴,則返回空字串。
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是「**.c** **.c**」。
## basename
```Shell
$(basename <names...>)
```
名稱:取前綴函數——basename。
功能:從文件名序列`<names>`中取出各個文件名的前綴部分。
返回:返回文件名序列<names>的前綴序列,如果文件沒有前綴,則返回空字串。
示例:$(basename **src/foo**.c **src-1.0/bar**.c hacks)返回值是「**src/foo** **src-1.0/bar** **hacks**」。
## addsuffix
```Shell
$(addsuffix <suffix>,<names...>)
```
名稱:加後綴函數——addsuffix。
功能:把後綴`<suffix>`加到`<names>`中的每個單詞後面。
返回:返回加過後綴的文件名序列。
示例:$(addsuffix .c,foo bar)返回值是「foo.c bar.c」。
## addprefix
```Shell
$(addprefix <prefix>,<names...>)
```
名稱:加前綴函數——addprefix。
功能:把前綴`<prefix>`加到`<names>`中的每個單詞後面。
返回:返回加過前綴的文件名序列。
示例:$(addprefix **src/**,foo bar)返回值是「**src/**foo **src/**bar」。
## join
$(join <list1>,<list2>)
名稱:連接函數——join。
功能:把`<list2>`中的單詞對應地加到`<list1>`的單詞後面。
如果`<list1>`的單詞個數要比`<list2>`的多,那麼,`<list1>`中的多出來的單詞將保持原樣。
如果`<list2>`的單詞個數要比`<list1>`多,那麼,`<list2>`多出來的單詞將被複製到`<list1>`中。
返回:返回連接過後的字符串。
示例:
$(join aaa bbb , **111** **222** **333**)返回值是「aaa**111** bbb**222** **333**」。
$(join aaa bbb , **111** **222** )返回值是「aaa**111** bbb**222**」。
$(join aaa bbb , **111** )返回值是「aaa**111** 」。
# Reference
http://deanjai.blogspot.com/2008/02/subst-subst-subst-eeeefeet-on-street.html