1. 程式人生 > >補基礎之shell 和makefile

補基礎之shell 和makefile

靜默 兩種 1.4 如果能 內置 字符 為我 賦值運算 循環

2.2.1、shell介紹

  • (1)shell可以理解為軟件系統提供給用戶操作的命令行界面,可以說他是人機交互的一種方式
  • (2)我們可以使用shell和操作系統、uboot等軟件系統進行交互。具體來說就是我們通過shell給軟件系統輸入命令,然後回車執行,執行完後會回到shell命令行再次輸入命令執行
  • (3)我們上述的操作方式一般情況下工作很好,但是有一個缺陷。譬如我們要在linux 下創建一個文件a.c,可以touch a.c,但是如果我現在要在linux下創建100個文件,分別是a1.c a2.c a3.c..............a100.c

如果這時候還是我們去命令行執行命令穿件也可以,但是很累。最好的做法就是把創建過程寫成一個shell腳本程序,然後去執行這個shell腳本程序,執行這個程序的效果和手工在命令行輸入哪些命令效果一樣的。(回憶在arm裸機中安裝交叉編譯工具鏈是,創建arm-linux-xxx的符號鏈接)

2.2.1.2、shell是一類編程語言

  • (1)編寫shell腳本是使用的語言就是shell語言,又叫做腳本語言
  • (2)shell腳本其實是一類語言而不是一個語言

2.2.1.3、常用的shell語言:sh、bash、 csh、ksh、perl、python等

  • (1)在linux下常用的腳本語言其實就是bash、sh
  • (2)perl、python這樣的高級shell腳本語言,常用在網絡管理配置領域,系統運維人員一般要學習這些
  • (3)腳本語言一般在嵌入式中應用,主要是用來做配置(一個復雜的嵌入式程序都是可配置的,配置過程就是用腳本語言來實現的)自然不會使用過於復雜的腳本語言特性,因此只需要針對性的學習即可
  • (4)linux下最常用的腳本就是bash,我們學習也是以bash為主

2.2.1.4、shell腳本的運行機制:解釋運行

  • (1)C語言(C++)這種編寫過程是:編寫出源代碼(源代碼是不能直接運行的)然後編譯鏈接形成二進制程序,然後才能運行了讓腳本程序不同,腳本程序編寫好後就源代碼可直接運行(沒有編譯鏈接過程)
  • (2)shell程序是解釋運行的,所謂解釋運行就是說當我們執行一個shell時,shell解析器會逐行的解釋shell程序代碼,然後一行一行的去運行。(順序結構)
  • (3)CPU實際上只認識二進制代碼,根本不認識源代碼,腳本程序源代碼其實也不是二進制代碼,CPU也不認識,也不能直接執行,只不過腳本程序的編譯鏈接過程不是以腳本程序源代碼位單位進行的,而是在腳本運行過程中逐行的解釋執行時才完成腳本程序源代碼轉成二進制的過程。(不一定是編譯鏈接,因為這行腳本程序可能早就編譯好了,這裏我們只是調用它)的。

2.2.2、動手寫第一個shell

2.2.2.1編輯器、編譯器、運行方法(腳本的3中執行方法)

  • (1)shell程序是文本格式的,只要是文本編譯器都可以。但是因為我們的shell是要在linux系統下運行的,所以換行符必須是‘\n’,而windows下的換行符是"\r\n",因此windows中的編輯器寫的shell不能在linux下運行。所以我們整個課程都是在linux下使用vi編輯器(實際上是vim)進行編寫調試的
  • (2)編譯器: 不涉及,因為shell是解釋性語言,直接編輯完就可以運行
  • (3)shell程序運行有多種方法,這裏介紹三種方法:

第一種:./xx.sh      和運行二進制可執行程序的方法一樣,這樣運行shell必須要求shell具有可執行權限。chmod a+k xx.sh來添加可執行權限

第二種:source xx.sh   source是linux的一個命令,這個命令就是用來執行腳本程序的,這樣運行時不需要腳本具有可執行權限

第三種:bash xx.sh    bash是一個腳本程序的解釋器,本質上是一個可執行程序。這樣執行相當於我們執行了bash程序,然後把xx.sh作為argv[1]傳給他運行

2.2.2.2、hello world程序的解釋

  • (1)shell程序的第一行一般都是:#!/bin/sh  這行話以#!開始,後面加上一個pathname,這行話的意思就是指定shell程序執行時被那個解釋器解釋執行。所以我們在這裏寫上/bin/sh意思就是這個shell將來被當前機器中/bin目錄下的sh可執行程序執行
  • 可以將第一行寫為;#!/bin/bash來指定使用bash執行該腳本。
  • 註意;在 ubuntu上面默認的解釋器sh其實不是bash;而是dash.dash是ubuntu中默認使用的腳本解釋器
  • (2)腳本中的註釋使用#, #開頭的行是註釋行,如果有多行需要註釋,每行前面都要就加#(#就相當是C語言//)
  • (3)shell程序的正文,由很多行shell語句構成

2.2.2.3、shell並不神秘

  • (1)shell就是把一圈命令行中鍵入執行的命令寫成了程序。shell其實就是為了避免反復的在命令行下手工輸入而發明的一種把手工輸入過程記錄下倆,然後通過執行shell腳本程序就能再次復述原來記錄的手工輸入過程的一種技術
  • (2)shell編輯完可以直接運行(不需要編譯)

2.2.3、shell編程學習1

2.2.3.1、shell中使用linux命令

  • (1)練習1:當前目錄下創建文件a.txt
  • (2)練習2:當前目錄下創建文件夾dir, dir下創建文件b.txt

總結:以上兩個練習的目的就是讓大家基本學會寫腳本,明白腳本編程其實就是把以前在命令行下輸入的命令挪到腳本程序中然後一次執行

2.2.3.2、shell中的變量定義和引用

  • (1)變量定義和初始化。shell是弱類型語言腳本語言(語言中的變量入股破有明確的類型就屬於強類型語言;變量沒有明確類型就是弱類型語言),和我們C語言不同。在shell編程中,定義白能量不需要指定類型,在shell中沒有類型這個概念,所以在shell中變量可以直接定義。
  • (2)變量定義是可以初始化,使用=進行初始化賦值。shell中賦值的兩邊=兩邊是不能有空格的。
  • 註意:shell對語法非常在意,非常嚴格。很多地方都是必須沒有或者必須有,而且不能隨意沒有空格
  • (3)變量賦值,變量定義後可以再次賦值,新的賦值會覆蓋老的賦值。shell中並不可以區分變量的定義和賦值,反正每個變量就是一個符號,這個符號的值就是最後一個給他賦值時的值
  • (4)變量引用。shell中引用一個變量必須使用$符號,$符號就是變量解引用符號

註意:$符號後面跟一個字符串,這個字符串就會被當作變量去解析。如果這個自婦女患沒有定義,執行時並不會報錯,而是吧這個變量解析為空。也就是說shell中沒有被定義的變量就相當於是一個定義並賦值為空的 變量

註意:變量引用的時候可以$var,也可以${var}。這兩種的區別在某些情況下只能用${var}而不能簡單的$var

2.2.3.3、shell中單引號和雙引號的區別

  • (1)shell中使用字符串可以不加雙引號直接使用,而且又空格也是可以的,但是缺陷是不能輸出"或者其他轉義字符
  • (2)shell中也可以使用單引號來表示字符串,也是直接使用的,不能輸出轉移字符
  • (1)單引號中:完全字面轉換(不可包含單引號本身)
  • (2)雙引號中:

$加變量名可以取變量值

反引號仍表示命令替換

\$表示$的字面值    輸出$符號

\`表示`的字面值

\"表示"的字面值

\\表示\的字面值

2.2.4、shell 編程學習2

2.2.4.1、shell 中調用linux命令

  • (1)直接執行
  • (2)反引號括起來執行,有時候我們在shell中調用linux命令是為了得到這個命令的返回值(結果值),這時候就適合用一對反引號(鍵盤上ESC鍵下面的那個按鍵,和~在一個按鍵上)來調用執行命令。

2.2.4.2、shell中的選擇分支結構

  • (1)shell的if語言用法很多,再次介紹常用的,其他感興趣的可以自己去學
  • (2)典型的if語言格式

if[表達式];then

   xxx

   yyy

   ...

else

   xxx

   ...

fi

  • (3)if的典型應用

判斷文件是否存在。 (-f) 註意[ ]裏面前後都必須要加空格,不能省略。舉例:if [ -f a.c ];

判斷目錄是否存在  (-d)

判斷字符串是否相等 ("str1" = "str2"),註意用一個等號而不是兩個

判斷數字是否相等(-eq)、大於(gt)、小於(lt)、大於等於(ge) 小於等於是(-le)  回憶一下在ARM裸機中講述ARM匯編條件執行時,曾經就用過這些條件判斷的縮寫(eq就是equal,gt就是greater than , lt就是less than, ge就是great or equal, le就是less or equal)判斷字符串是否為空(-z)

  判斷字符串是否為空(-z)

註意-z判斷是如果變量本身沒定義也是不成立的(也就是說-z認為沒定義就不等於空)

舉例:

#!/bin/sh
if
[12 -eq 12];then                  echo "yes"                  
 else
    
echo "no"
fi
#!/bin/sh
str =""
if [-z  $str];then
            echo "yes"
else
            echo "no"
fi
  • (4)if 判斷中使用“-o”表示邏輯或 。if [ 12 -eq 12 -o "abcd" = "abcd"];then

相當於C語言中在if後面的條件中用裸機與、邏輯或來鏈接2個式子,最終if中是否成立取決於2個式子的邏輯結果

  • (5)邏輯與&&和邏輯或||與簡寫的if表達式。[ -z $str ] || echo "fei kong"

2.2.5、shell中的循環結構

2.2.5.1、for循環

  • (1)要求:能看懂、能改即可。不要求能夠完全不參考寫出來。因為畢竟嵌入式並不需要完全重新手寫shell,系統管理員(服務器運維人員,應用層系統級管理開發的才需要完全掌握shell)

2.2.5.2、while循環

  • (1)和C語言的循環在邏輯上無差別
  • (2)要註意很多格式要求,譬如:while後面的[ ]兩邊都有空格,[ ]後面有分號(如果do放在一行的話),i++的寫法中有兩層括號

2.2.5.3、echo的創建和追加輸入文件

  • (1)在shell中可以直接使用echo指令新建一些文件,並且將一些內容寫到這些文件中去。創建文件並輸入內容的關鍵就是>。
  • (2)還可以使用echo指令配合追加符號>>向一個已經存在的文件末尾追加輸入內容

2.2.6、shell中的其他值得關註的知識點

2.2.6.1、case語句

  • (1)shell中的case語句和C語言中的switch case 語句作用一樣,格式有差異
  • (2)shell中的case語句天生沒有break,也不需要break。和C語言中的switch case butong .shell中的case默認就是匹配上那個就執行那個,不會說執行完了還去執行後面其他的case(就好像shell中的case語言默認都帶了break)

2.2.6.2、調用shell程序的傳參

  • (1)C語言中可以通過main函數的argc和argv給程序傳參
  • (2)shell程序本身也可以在調用時傳參給他。在shell程序內部使用也是使用一些特定符號來表示的。

包括:$#表示調用該shell時傳參的個數。($#計數時只考慮真正的參數個數)

$0、$1、$2.....則依次表示傳參的各個參數

C語言:./a.out  aa bb cc argc = 4, argv[0] =./a.out argv[1] = aa ...............

shell:source a.sh aa bb cc $# = 3  $0是執行這個shell程序的解析程序的名字。 $1表示第一個有效參數的值, $2是第二個有效參數的值........

主要;shell中的很多語法特性和C語言中是相同的,也有很多是不同的。所以大家學的越多越容易混淆(本質原因還是用的不熟悉,用的少),解決方案是:做總結。做筆記,多寫代碼經常用。

2.2.6.3、while循環和case語言和傳參結合

  • (1)shell中的break關鍵字和C語言中意義相同(都是跳出)但是用法不同。因為shell中的break只用於循環跳出。所以當while中內嵌case語句時,case中的break是跳出最外層循環的,不是跳出case語句的。
  • (2)shell中的$# $1等內置變量的值不是不可變的,而是可以被改變的額,被shift指令改變。shift指令有點像左移運算符,把我們給shell程序的傳參左移了一個一出去了,原來的$2變成了$1,原來的$#少了一個

2.2.7、Makefile基礎回顧

2.2.7.1、Makefile的作用和意義

  • (1)工程項目中C文件項目太多,管理不方便,因此用Makefile來做項目管理,方便編譯鏈接過程
  • (2)uboot和linux kernel本質上都是V語言的項目,都由很多個文件組成,因此都需要通過Makefile來管理。所以要分析uboot必須對Makefile有所了解

2.2.7.2、目標、依賴、命令

  • (1)目標就是我們要去make xxx的那個xxx,就是我們最終要生成的額東西
  • (2)依賴是用來生成目錄的原材料
  • (3)命令就是加工方法,所以make xxx的過程其實就是使用命令將依賴加工成目標的過程

2.2.7.3、通配符%和Makefile自動推導(規則)

  • (1)%是Makefile中的通配符,代表一個或幾個字母。也就是說%.o就代表所有的以.o位結尾的文件
  • (2)所謂的自動推導其實就是Makefile的規則。當Makefile需要某一個目標時,他會把這個目標去套規則說明,一旦套衫了某個規則說明,則Makefile會試圖尋找這個規則中的依賴,如果能找到則會執行這個規則用依賴生辰目標

2.2.7.4、Makefile中的定義和使用變量

  • (1)偽目標意思是這個目標本身不代表一個文件,執行這個目標不是為了得到某個問您或者東西,而是單純的為了執行下面的這條指令。
  • (2)為目標一般都沒有依賴,因為執偽目標就是為了執行目標下面的命令。既然一定要執行下面的命令了,那就不必加依賴,因為不加依賴意思就是無條件執行。
  • (3)偽目標可以直接寫,不應想使用,但是有時候為了明確聲明這個目標是個偽目標會在偽目標的前面用 .PHONY來聲明它是偽目標

2.2.7.6、Makefile的文件名

  • (1)Makefile的文件名合法的一般有2個:Makefile或者makefile

2.2.7.7、Makefile中引用其他Makefile(include指令)

  • (1)有時候Makefile總體比較復雜,因此分成好幾個Makefile來寫。然後在主Makefile中引用其他的,用include指令來引用。引用的效果也是原地展開,和C語言中的頭文件包含非常相似

2.2.8、Makefile補充學習1

2.2.8.1、Makefile中的註釋用#

  • (1)Makefile中註釋使用#,和shell一樣

[email protected]

  • (1)[email protected]
  • (2)Makefile中靜默情況下再執行一行命令前會先把這行命令給打印出來,然後再執行命令
  • (3)如果你不想看到命令本身,指向看到命令執行就靜默執行即可

2.2.8.3、Makefile中幾種變量賦值運算符

  • (1)=    最簡單的賦值
  • (2):=    一般也是賦值

以上這兩個大部分情況下效果是一樣的,但是有時候不一樣

用 = 賦值的變量,在被解析時他的值取決於最後一次賦值時的值,所以你看變量引用的值不能往前看,應該往後看。

用 := 來賦值的,則是就地直接解析,只用往前看即可。

  • (3)?=

如果變量前面並沒有賦值過則執行這條賦值,如果前面已經賦值過了則本行被忽略。(實驗可以看出:所謂的沒有賦值過其實就是這個變量沒有被定義過)

  • (4)+=

用來給一個已經賦值的變量接續賦值,意思就是把這次的值加到原來的值後面,有點類似於strcat。(在shell makefile等文件中,可以認為所有變量都是字符串,+=就是相當於給字符串strcat接續內容)(註意一個而細節,+=續接的內容和原來的內容之間會自動加一個空格隔開)

註意:Makefile中並不要求賦值運算符兩邊一定要有空格或者無空格,這一點比shell的格式要求寬松一些。

2.2.8.4、Makefile的環境變量

  • (1)Makefile中用export導出到就是環境變量。一般情況下,要求環境變量名用大些,其他的普通變量名用小寫。
  • (2)環境變量和普通變量不同,可以這樣理解:環境變量類似於整個工程中所有Makefile之間可以共享的全局變量,而普通變量知識當前本Makefile中使用的局部變量。所以要註意:定義了一個環境變量會影響到工程中別的Makefile文件,因此要小心
  • (3)Makefile中都有一些環境變量可能是Makefile本身自己定義的內部的環境變量(譬如我們在make執行時給makefile傳參。 CC=arm-linux-gcc,其實就是貴當前Makefile傳了一個環境變量CC,值是arm-linux-gcc.我們在make是給makefile傳的環境變量值優先級是最高的,可以覆蓋makefile中的賦值)。這就好像C語言中編譯器預定義的宏__LINE__ __FUNCTION__等一樣。

2.2.9、Makefile補充學習2

  • 2.2.9.1、Makefile中使用通配符

  • (1)*    若幹個任意字符   echo *.c
  • (2)?    1個任意字符 echo ?.c
  • (3)[ ]    將[ ]中的字符依次去和外面的結合匹配  echo [12].c

還有個%,也是通配符,表示任意多個字符,和*很相似,但是%一般只用於規則描述中,又叫做規則通配符。

2.2.9.1、Makefile的自動變量

  • (1)為什麽使用自動變量。在有些情況下文件集合中文件非常多,描述的時候很麻煩,所以我們Makefile就用一些特殊的符號來代替符合某種條件的文件集,這就形成了自動變量
  • (2)自動變量的含義:預定義的特殊意義的符號
  • (3)常見自動變量:

[email protected]  規則的目標文件名

$<    規則的依賴文件名。如果依賴的目標是以模式(即%)定義的,那麽“$<”將是符合模式的一系列的文件集。主要,其是一個一個取出來的。

$^    依賴的文件集合

補基礎之shell 和makefile