目錄
1. 環境變量
1.1 概念介紹
1.2 命令行參數?
1.3? 一個例子,一個環境變量
1.4?認識更多的環境變量
1.5?獲取環境變量的方法
a. 指令操作
b. 代碼操作
1.6?理解環境變量的特性
a.環境變量具有全局特性
b.補充兩個概念(為后面埋一個伏筆)
1. 環境變量
1.1 概念介紹
? 環境變量(environment variables)?般是指在操作系統中用來指定操作系統運行環境的?些參數
? 如:我們在編寫C/C++代碼的時候,在鏈接的時候,從來不知道我們的所鏈接的動態靜態庫在哪 里,但是照樣可以鏈接成功,生成可執行程序,原因就是有相關環境變量幫助編譯器進行查找。
? 環境變量通常具有某些特殊用途,還有在系統當中通常具有全局特性
1.2 命令行參數?
下面我們先來做一個實驗,我們都知道在C/C++中,main函數其實是有兩個參數的(int argc,char* argv[ ]),字符指針在C語言中要么存有一個字符的地址,要么表示一個字符串的首地址,argv表示數組中存有字符串,而argc表示字符串的個數。
下面的代碼表示將數組中的所有字符串打印下來:
下面是實驗結果:?
根據結果我們可以發現有某種東西將我們命令行上面的命令(包含空格的字符串)以空格為分隔符分離成多個字符串,并保存在argv數組中。
下面我們再來寫一個代碼:
#include <stdio.h>
int main(int argc,char *argv[])
{if(argc!=2){printf("usage:%s [-a|-b|-c]\n",argv[0]);}return 0;
}
?以上代碼是在用戶沒有正確使用該命令時告訴用戶使用該命令的時候需要帶上【-a -b -c】其中的一個選項。
?所以我們就可以用main函數的命令行參數來實現程序的各種不同子功能【這也是指令選項的實現原理】。
總結:每個進程都有一張argv表,用來實現選項功能,以往我們沒有關心main函數的命令行參數是因為我們寫的程序不需要這些需求。?
小問題:我們在命令行中寫的長字符串是被誰切分了呢?
這里直接說結果:用戶每次登入系統時都會自動創建一個bash進程,該進程會幫組我們解析命令行中的長字符串。【具體bash是如何做到的我暫時還不知道呢!以后再告訴你們】
1.3? 一個例子,一個環境變量
系統預裝指令【ls、mkdir】VS 自己寫的程序
我們在使用系統級指令時,直接用它們的名稱即可。但是當我們要執行自己寫的程序時,必須要指明該指令的路徑【相對路徑或絕對路徑】。我們都知道,要執行一個程序,必須先找到它。但是這里有一個問題,系統級指令是如何根據指令名稱找到該指令的呢?
先說結論:系統中存在環境變量,來幫助系統找到目標二進制文件!
系統級指令在usr/bin/目錄下,如果我們的指令也在該目錄下也就可以和系統級指令一樣不用指明路徑了。
自己寫的程序有很多未知性,所以我們還是不要把他放到該目錄下!?
?好,接下來我們來認識一下第一個環境變量PATH
PATH是系統中默認搜索指令的路徑。?
其中的冒號將每一個默認搜索路徑分隔開來,當我們命令行中執行一個命令時,系統會根據PATH環境變量中的默認路徑【從第一個路徑開始】來查找是否存在該命令。?如果存在,則執行,否則輸出該命令未被找到。
既然如此,那如果我們將自己的路徑添加到PATH環境變量中,那我們的指令是不是也可以和系統級指令那般直接使用呢?
當然可以,我們直接修改PATH=路徑
但是這樣系統級指令就找不到了,不過我們關掉xshell重新登入PATH就恢復了
如果我們希望只添加路徑的話,如下操作可以辦到,當重新登入也會恢復原樣:
?至于為什么會回復原樣,我們需要對環境變量有更加深刻的理解!
接下來,我們從存儲的角度理解環境變量。
先說結論,在用戶登入系統時,bash進程會形成一張表->【環境變量表】,這張表的結構和命令行參數表完全相同【都是字符指針數組】。
env命令可以查看系統當中的所有環境變量,而環境變量表中存儲著這些內容!
所以,環境變量就是bash進程內部malloc的一段空間,而這段空間存儲的內容就是一個一個的字符串【環境變量】?。
至此,我們就可以理解當我們在命令行當中敲下ls -al命令時,ls -al的基本執行流程了:bash進程首先拿到“ls -al”字符串,然后切分形成命令行參數表,接著根據解析完成后的字符串到環境變量表當中找到PATH環境變量,根據PATH默認的路徑下找該命令,找到即執行,沒找到則報錯。
那環境變量最開始從哪里來的呢?->[如果不登入就沒有bash進程]
先說結論:從系統相關的配置文件中來的!
bash進程創建時就會從配置文件中拿到所有的環境變量并創建一張表!這就是我們上面說到的修改PATH環境變量為什么在重新登入時就會恢復原樣的原因。
好,那我們就來看一下什么是配置文件!
在每個Linux用戶的家目錄下都有一個.bashrc的隱藏文件。
該文件下的100多行都是先關的配置信息。?
那如果我們將自己的路徑添加到配置文件中的PATH值的時候,是不是每次登入時自己寫的程序可以和系統級指令一樣使用呢!當然如此!這里就不演示了。
1.4?認識更多的環境變量
。HOME環境變量
指定用戶的家目錄(即用于登入Linux系統時,默認的家目錄)
。LOGNAME? |? USER 【登入用戶 | 用戶】
。HISTSIZE?
記錄我們歷史上敲的最新1000行命令
。PWD? |? OLDPWD [當前工作路徑 | 上一次工作路徑]
這也是我們使用cd -可以來回切換工作路徑的原因,系統已經幫我們記錄好了。
最后,我們在回到環境變量的概念:環境變量(environment variables)?般是指在操作系統中用來指定操作系統運行環境的?些參數
此時,我們就會對這個概念有更加深刻的理解了,我們會發現每一種環境變量都有其特定的功能,有的是記錄當前用戶的,有的是記錄歷史指令的,有的是幫我們找指令的默認路徑的,還有的是記錄主機名,記錄當前工作路徑……而這些環境變量都是系統提供的,并且這些環境變量本質上是給bash進程使用,這也是間接的給用戶使用了!
1.5?獲取環境變量的方法
a. 指令操作
上面我們使用過了env【查看所有環境變量】,echo +環境變量名【查看某個環境變量】就不多說了。
export【向環境變量表中導入自己寫的環境變量】
?unset【取消某個環境變量】
b. 代碼操作
1.main函數的第三個命令行參數char *env
我們之前說main函數有兩個參數,其實還有第三個參數env,這個參數繼承了父進程bash的環境變量表,所以我們也可以通過這個參數拿到所有的環境變量。
?因為子進程會繼承父進程bash的環境變量表,所以如果我們修改bash的環境變量,那么子進程的環境變量也會隨之修改。
bash進程環境變量表修改后:
?子進程的環境變量表:
既然如此,bash的孫子進程,曾孫進程等等都會基礎bash的環境變量表。
所以說:環境變量通常具有某些特殊用途,還有在系統當中通常具有全局特性
2.getenv【系統調用】
給該函數傳遞環境變量名,該函數就會返回字符串地址【該環境變量的內容】。即可以獲得指定環境變量的內容。
上面我們說過:子進程會繼承父進程的環境變量,為什么要這樣設計呢?
這是為了讓我們的進程可以根據環境變量做個性化的操作!下面舉一個栗子:
如果我們希望寫一個只有我們自己才能運行的程序,該怎么寫呢?
我們都知道,系統當中只有bash進程認識當前用戶是誰【在環境變量USER當中記錄著】,所以我們可以通過獲取該環境變量的方式來控制我們的程序邏輯進而實現只有自己登錄系統時才能運行該程序的目的。
用戶是user2時:?
用戶是root時:? ? ??
3. environ 【全局的二級指針】
該指針指向環境變量表的首地址,所以是二級指針。所以我們也可以通過它來獲取所有的環境變量。
1.6?理解環境變量的特性
a.環境變量具有全局特性
(前面已經說明過這個特性了,這里就不贅述了)
b.補充兩個概念(為后面埋一個伏筆)
1.本地變量
我在命令行中直接定義變量i=10,發現echo命令也可以查看到該變量,但是該變量并不是環境變量,沒有記錄到環境變量表當中。
但是我們可以用set命令同時查看環境變量和本地變量。
本地變量與環境變量不同,并不會被子進程繼承,而只是在bash內部被使用。
2.我們的環境變量是在誰里面?bash!
export是把自己寫的環境變量導入到父進程bash里面。
而子進程怎么會導數據到父進程里面呢?這也太奇怪了!
原因就在于export是內建命令【built-in command】執行該指令時,不需要創建子進程,而是讓bash自己親自執行【bash自己調用函數或者系統調用完成】。