1. 程式人生 > 其它 >make和shell入門

make和shell入門

make基礎

1. make的顯式規則

在Linux作業系統下程式設計時,通常利用make命令來自動完成編譯工作。Make命令根據一個稱為makefile的檔案來完成並自動維護編譯工作。Makefile檔案需要按照某種語法進行編寫,其中說明了如何編譯各個原始檔並連結生成可執行檔案,並定義了原始檔之間的相互依賴關係。當修改了其中某個原始檔時,如果其他原始檔依賴於該檔案,則也要重新編譯所有依賴該檔案的原始檔。

Makefile檔案中包含一些規則來告訴make處理哪些檔案以及如何處理這些檔案。規則主要是描述哪些檔案(target目標檔案)是從哪些別的檔案(dependency依賴檔案)中產生的,以及用什麼命令(command)來執行這個過程。Makefile規則的一般形式如下:

target:dependencydependency
(tab)  <command>

目標檔案(target)通常是可執行檔案或中間檔案,但也可以是要執行的動作,如“clean”。
依賴檔案(dependency)列表通常是編譯目標檔案所依賴的其他檔案。
命令(command)是建立target檔案所需要執行的步驟,比如編譯命令,每個命令佔一行,起始字元必須為TAB字元。

test: prog.ocode.o
   gcc –o test prog.o code.o
prog.o: prog.c prog.h code.h
   gcc –c prog.c –o prog.o
code.o: code.c code.h


   gcc –c code.c –o code.o
clean:
   rm –f *.o

左圖的makefile示例中共定義了四個目標:test、prog.o、code.o和clean。目標檔案與依賴檔案用":"分隔,多個依賴檔案以空格隔開,然後另起一行以tab開頭給出實現目標的命令。當命令過長時,使用"\"作為續行符。

例中已完成的程式原始碼為prog.c,prog.h,code.c,code.h,首先要使用make testmake(預設編譯makefile檔案中第一個目標)編譯程式。由於test依賴的prog.o和code.o檔案不存在,所以要先執行gcc –c prog.c –o prog.o

gcc –c code.c –o code.o生成這2個檔案。最後再執行gcc –o test prog.o code.o生成test。make clean用於清除編譯過程的中間檔案,這通常是約定俗成的做法。

2. make變數的用法

在一行的開始給初變數名字,後面跟一個":="及要設定的值,即可定義變數:
VARNAME:=string
使用時把變數用括號{}括起來,並在前面加上$:
${VARNAME}

使用方法如下:

OBJS:=prog.o code.o
CC:=gcc
test: ${OBJS}
    ${CC} –o test ${OBJS}
prog.o: prog.c prog.h code.h 
    ${CC} –c prog.c –o prog.o 
code.o: code.c code.h 
    ${CC} –c code.c –o code.o 
clean: 
    rm–f *.o

Makefile檔案中還可以使用環境變數,以及預定義變數,如$@(目標名)、$^(所有的依賴檔案)、$<(第一個依賴檔案),
例如:
demo.o: demo.c demo.h
可以寫成:
gcc-c $< -o $@

3. make的隱式規則

make進行編譯時遵循一些稱作隱含規則的內建規則,這些規則在makefile中並沒有被完整地給出,但make知道沒有被給出的部分是什麼。(我理解為隱式規則可以不用給出)

典型的隱含規則給出了由.c檔案如何生成.o檔案,被隱含的規則是:
%.o: %.c
  ${CC} ${CFLAGS} $< -o $@

依據上面的隱含規則,前面的變數介紹中的示例程式碼可以省略為如下內容:

OBJS:=prog.o code.o
CC:=gcc 
CFLAGS:=-c 
test:${OBJS} 
    ${CC} –o $@ $^
prog.o: prog.c prog.h code.h
code.o:code.c code.h
clean: 
    rm –f *.o

shell基礎

Shell也有多種不同的版本:
sh:GNU Bourne Shell
bash:GNU Bourne Again Shell(PC預設)
Korn Shell:大部分與BourneShell相容。
C Shell:是SUN公司Shell的BSD版本。
ZShell:集成了bash、ksh的重要特性。

通常在shell程式開始宣告型別,如 #!/bin/sh#!/bin/bash

1. shell的四個變數

1.1 使用者變數

shell允許把值存在變數中,shell變數名以字母或下劃線字元開始,由字母、數字或下劃線組成。要把值存入變數,只要寫出變數名,或緊跟一個=,再加變數值即可。
例如:variable=value
    count=1
在程式中使用變數的值時,要在變數名前面加上一個符號“$”。
例如:echo $variable(echo的意思是列印後面的變數)

1.2 環境變數

環境變數是一種特殊的變數,可以由其他程式傳遞給指令碼,在指令碼中被呼叫的任何程式都將繼承環境變數。可以像定義一個變數一樣來設定環境變數,在標記它為環境變數時需要使用“export”命令:
   export MYENV=1
   echo $MYENV
使用set命令可以獲取當前上下文中全部的環境變數,使用env命令可以檢視系統中全部環境變數

1.3 位置變數

由出現命令列上的位置確定的引數稱做位置引數。總共有十個位置引數,其對應的名稱依次是$0,$1,$2,...$9,其中$0表示命令名或Shell指令碼名,不可或缺,其它位置引數可有可無。
編輯ison指令碼檔案內容如下:
   who | grep $1
執行:chmod + x ison
   ./ison bc

shell將用bc取代$1,命令列變為
   who | grep $bc

1.4 預定義變數

$#變數用於存放命令列中所鍵入的引數個數
$*變數可以引用傳遞給程式的所有引數

其中shift命令的作用是把位置引數左移,原來$1中的值丟失,引數變數的個數自動減1

$@變數和$*變數功能基本相同

$?變數: 每當程式執行完成後都會給系統返回一個退出狀態。該狀態是個數值,通常指示該命令執行是否成功。退出狀態為0表示執行成功,非零表示執行失敗。shell自動將最後所執行命令的退出狀態設定到shell變數$?中,可以用echo命令在終端上顯示它的值。

2. shell特殊字元與表示式

2.1 三種萬用字元

  1. *星號,它匹配任意字元的0次或多次出現。但注意,檔名前面的圓點(.)和路徑名中的斜線(/)必須顯式匹配。
  2. ?問號,匹配任意一個字元
  3. []一對方括號,其中有一個字元組。其作用是匹配該字元組所限定的任意一個字元。
    注意*和?在方括號內,就不是萬用字元了。!歎號,若它緊跟在一對方括號的左方括號[之後,則表示不在一對方括號中所列出的字元。

2.2 引號與反斜線

  1. 雙引號""括起來的字元,除$、倒引號和反斜線(\)仍保留其功能外,其餘字元通常作為普通字元對待。
  2. 單引號''括起來的字元都作為普通字元出現。
  3. 倒(反)引號``用於設定系統命令的輸出到變數,反引號中的內容作為一個系統命令並執行。
  4. 反斜線\為轉義字元,若想在字串中使用反斜線本身,則必須採用(\\)的形式。

2.3 表示式

  1. 邏輯表示式:
       && : 與
       || : 或
       ! : 非(需要有空格)
  2. expr求值表示式
    expr命令一般用於整數值,但也可用於字串。一般格式為:expr argument operator argument 其中operator為 + - * / %,但對*的使用要用轉義符\。
    示例如下:
       v1=3
       v2=2
       v3=`expr $v1 * $v2 `
       echo $v3
    結果輸出6

3. shell條件判斷

3.1 if表示式

下面是if表示式的一般結構
if   command1
then
   ...
elif  command2
then
   ...
else
   ...
fi
command1和command2需要執行並檢測其退出狀態,如果退出狀態為0(command為真),則執行其後的then語句,否則就跳到else或者elif或fi。

下面是if用法的示例:

其中:
int1 –gt int2表示int1 大於int2
int1 –lt int2表示int1 小於int2

3.2 case表示式

case用法結構如下:
case string in
   string1 )
      ...;;
   string2 )
      ...;;
   * )
      ...;;
esac
字串string首先與string1和string2比較,如果匹配就執行它們下面的語句直到雙分號。如果都不匹配,則執行* )下面的語句。
下面是case用法的示例:

4. shell迴圈

4.1 for迴圈

for迴圈分為帶列表和不帶列表的。
帶列表將一組命令迴圈執行預先確定的次數,基本方法如下:

不帶列表的形式,shell會自動將命令列鍵入的所有引數依次組織成列表。

4.2 while迴圈

while迴圈示例如下:

break命令與continue命令與C中相應命令功能相同。

5. shell函式

和“真正的”程式語言一樣,shell也有函式,雖然在某些實現方面稍有些限制。
函式被呼叫或被觸發,只需要簡單地使用函式名即可。
函式示例如下: