Linux命令行參數(shù)和環(huán)境變量使用詳解
1. 命令行參數(shù)
首先,我們要解決一個(gè)問題:main函數(shù)可以有參數(shù)嗎?
答案是,可以的。

很多人可能第一次見到main函數(shù)還有參數(shù),也有人只知道有參數(shù),但不知道它代表的到底是什么意思。

我們用這一段代碼先來看看現(xiàn)象:

從終端的輸出結(jié)果可以看出,隨著你在命令后面輸入的參數(shù)增多,argc(參數(shù)計(jì)數(shù)器)不斷增加,argv(參數(shù)向量數(shù)組)里存的內(nèi)容也越來越多:
輸入 ./code:
argc: 1:說明只有 1 個(gè)參數(shù)(系統(tǒng)默認(rèn)自帶的程序名)。argv[0] -> ./code:argv[0]永遠(yuǎn)固定存儲 程序自身的名稱或路徑。
輸入 ./code a:
argc: 2:參數(shù)變成了 2 個(gè)(程序名 + 第一個(gè)自定義參數(shù))。argv[1] -> a:argv[1]存儲了你輸入的第一個(gè)自定義參數(shù)a。
這段現(xiàn)象背后,是 Linux 系統(tǒng) exec 執(zhí)行流程 的體現(xiàn):
命令拆分(Shell 解析):當(dāng)你在終端輸入 ./code a b c 并回車時(shí),Shell(命令行解釋器)會先把這行字符串按 空格 拆分成一個(gè)字符串?dāng)?shù)組:[ "./code", "a", "b", "c" ]
傳遞給 main 函數(shù):Shell 調(diào)用系統(tǒng)調(diào)用執(zhí)行程序,操作系統(tǒng)內(nèi)核會把這個(gè)數(shù)組作為參數(shù),原封不動地傳給 main 函數(shù)。
參數(shù)封裝:
argc:內(nèi)核數(shù)一下這個(gè)數(shù)組里有幾個(gè)元素,傳給argc(這里是 4 個(gè))。argv:內(nèi)核把這個(gè)字符串?dāng)?shù)組的首地址傳給argv。argv[argc] = NULL:C 語言標(biāo)準(zhǔn)規(guī)定,argv數(shù)組的最后一個(gè)元素后面必須跟一個(gè)NULL指針,作為參數(shù)結(jié)束的標(biāo)記(雖然代碼里沒打印,但它存在)。
argc 記錄了命令行輸入的參數(shù)總個(gè)數(shù),包含程序名本身;argv 是一個(gè)字符串指針數(shù)組,依次存儲了從命令行解析出來的每一個(gè)參數(shù),argv[0] 固定為程序的名稱或路徑,argv[1]、argv[2] 等則依次存儲用戶輸入的自定義參數(shù)。程序通過這兩個(gè)參數(shù),能夠精準(zhǔn)獲取運(yùn)行時(shí)的命令行輸入數(shù)據(jù),實(shí)現(xiàn)程序與操作系統(tǒng)的交互。
那么說到底,這兩個(gè)參數(shù)到底有什么用呢?
我們先給大家看一個(gè)場景:


首先利用這段代碼,我們實(shí)現(xiàn)出這樣一個(gè)場景,這樣看可能不太直觀,但是這樣大家就能理解了:

因此,命令行參數(shù)的意義在于:讓同一個(gè)程序能靈活適配不同場景,無需修改源碼。它讓程序在啟動時(shí)就能獲取用戶指定的配置、目標(biāo)文件、功能選項(xiàng)等,既提升了程序的通用性與復(fù)用性,也讓程序能便捷地與 Shell 腳本、其他工具聯(lián)動,適配自動化、批量執(zhí)行等場景,是 Linux 環(huán)境下程序與系統(tǒng)、用戶交互的標(biāo)準(zhǔn)化、高效接口。
2. 環(huán)境變量
我們之前提到過,當(dāng)我們想要執(zhí)行一個(gè)我們自己編寫的可執(zhí)行程序的時(shí)候,需要加上 ./ ,這是因?yàn)橐嬖V系統(tǒng):要執(zhí)行的程序就在當(dāng)前目錄,否則系統(tǒng)會提示 “command not found”。簡單說,./ 的作用就是指定從當(dāng)前目錄執(zhí)行程序。
可我們之前還講過,Linux下一切皆文件,像我們平時(shí)使用的命令,比如:ls、cd、touch等等,它們也都是作為可執(zhí)行程序的文件,為什么就不用加 ./ 呢?這是因?yàn)樗鼈兌挤旁谙到y(tǒng)里的一個(gè)目錄 user/bin/底下,當(dāng)執(zhí)行可執(zhí)行程序的時(shí)候,系統(tǒng)只會在這個(gè)目錄下查找文件。所以我們想要執(zhí)行可執(zhí)行程序文件的時(shí)候,除了采用 ./ 這種方式,還可以把們要執(zhí)行的文件放到 user/bin/這個(gè)目錄里面,就可以不加 ./ 直接調(diào)用。
那操作系統(tǒng)是怎么知道,自己就要在 user/bin/ 這個(gè)目錄下查找文件的呢?是誰告訴它的?
這就要介紹我們這一段的標(biāo)題:環(huán)境變量。
2.1 基本概念
環(huán)境變量是操作系統(tǒng)為當(dāng)前用戶會話、Shell 進(jìn)程以及所有運(yùn)行中的程序提供的一組全局動態(tài)變量,用于存儲系統(tǒng)運(yùn)行所需的公共配置信息,它不依賴于某個(gè)具體程序,而是對整個(gè)當(dāng)前環(huán)境生效,系統(tǒng)和應(yīng)用程序都可以直接讀取、使用這些變量來決定自身的運(yùn)行行為。
在 Linux 系統(tǒng)中,環(huán)境變量本質(zhì)是一組 “鍵 = 值” 形式的配置項(xiàng),常見的如 PATH 記錄可執(zhí)行文件搜索路徑、HOME 記錄用戶主目錄、PWD 記錄當(dāng)前所在目錄、LANG 決定系統(tǒng)語言與字符編碼等,它們的作用是讓程序不必在代碼中寫死固定路徑或配置,從而具備更好的通用性和可移植性。
當(dāng)我們在終端輸入一個(gè)命令時(shí),系統(tǒng)會根據(jù) PATH 這個(gè)環(huán)境變量里保存的目錄依次查找對應(yīng)可執(zhí)行文件,這也是為什么系統(tǒng)命令可以直接運(yùn)行,而自己編寫的程序需要加上 ./ 來明確指定路徑的原因。環(huán)境變量可以臨時(shí)設(shè)置,也可以寫入配置文件永久生效,不同用戶可以擁有不同的環(huán)境變量配置,它是系統(tǒng)實(shí)現(xiàn)靈活管理、程序間信息傳遞以及命令行正常工作的重要基礎(chǔ)機(jī)制。
常見的環(huán)境變量有這些:
PATH: 指定命令的搜索路徑HOME: 指定用戶的主工作目錄 (即用戶登陸到 Linux 系統(tǒng)中時(shí),默認(rèn)的目錄)SHELL: 當(dāng)前 Shell, 它的值通常是 /bin/bash。
2.2 查看環(huán)境變量
既然有環(huán)境變量這個(gè)東西,那我們該如何具體查看它呢?那就需要使用這個(gè)命令,以PATH為例:
echo $PATH
![]()
PATH 是 Linux 中用于指定命令搜索路徑的環(huán)境變量,它存儲了一組用冒號分隔的系統(tǒng)目錄,Shell 執(zhí)行命令時(shí)會按順序在這些目錄中查找可執(zhí)行文件,系統(tǒng)命令因存放在 PATH 包含的目錄中而可直接執(zhí)行,自定義程序不在 PATH 中,因此需要用 ./ 指定路徑運(yùn)行,是 Linux 實(shí)現(xiàn)命令查找與執(zhí)行的核心機(jī)制。
那么如果我們想要修改 PATH ,除了將我們的目標(biāo)文件直接加入到 user/bin/ 目錄里,還可以這樣操作:
# 把當(dāng)前目錄(.)追加到 PATH 末尾 export PATH=$PATH:.
不過這種修改只對當(dāng)前終端會話有效,關(guān)閉終端后就會恢復(fù)默認(rèn)。如果想要永久修改PATH,就要修改一下Shell 配置文件:
1. 編輯 ~/.bashrc 文件
vim ~/.bashrc
2. 在文件末尾添加
# 把你的程序目錄加入 PATH,比如 ~/mycode export PATH=$PATH:~/mycode
3.保存后執(zhí)行 source ~/.bashrc 讓配置立即生效。
不過一般不建議把當(dāng)前目錄 . 永久加入 PATH,因?yàn)闀嬖诎踩L(fēng)險(xiǎn),比如惡意腳本偽裝成 ls 等系統(tǒng)命令,被優(yōu)先執(zhí)行,臨時(shí)使用是可以的。另外,修改 PATH 時(shí)一定要寫 $PATH:比如 export PATH=xxx 會直接覆蓋原來的 PATH,導(dǎo)致所有系統(tǒng)命令都找不到,必須用 $PATH:xxx 追加。
如果還想查看其他所有的環(huán)境變量,我們可以使用 env 命令:

這里的環(huán)境變量的意義都是:
env:這是命令本身,作用是列出當(dāng)前所有環(huán)境變量。SHELL=/bin/bash:指定當(dāng)前使用的 Shell 解釋器為 bash。USER=chen:當(dāng)前登錄的用戶名是chen。HOME=/home/chen:當(dāng)前用戶的主目錄,也是登錄后默認(rèn)進(jìn)入的目錄。PWD=/home/chen:當(dāng)前所在的工作目錄路徑。PATH=/usr/local/bin:/bin:/usr/bin:...:命令搜索路徑,Shell 會按順序在這些目錄中查找可執(zhí)行文件。HOSTNAME=chen:當(dāng)前主機(jī)的名稱。TERM=xterm:當(dāng)前終端的類型,影響命令行的顯示和交互。LANG=en_US.UTF-8:系統(tǒng)的語言和字符編碼設(shè)置,決定輸出語言和文本處理方式。HISTSIZE=1000:Shell 歷史命令記錄的最大條數(shù)。HISTCONTROL=ignored:控制歷史命令的記錄方式,這里表示忽略重復(fù)命令。MAIL=/var/spool/mail/chen:用戶郵件文件的存儲路徑。LOGNAME=chen:與USER類似,記錄當(dāng)前登錄的用戶名。SHLVL=1:當(dāng)前 Shell 的嵌套層級,1 表示首次登錄的 Shell。LESSOPEN=||/usr/bin/lesspipe.sh %s:配置less命令的預(yù)處理工具,用于查看壓縮文件等。_=/bin/env:上一條執(zhí)行的命令路徑,這里是env命令本身。
2.3 通過代碼獲取環(huán)境變量
我們前面在講命令行參數(shù)的時(shí)候,提到了main函數(shù)有兩個(gè)參數(shù),實(shí)際上main函數(shù)最多有三個(gè)參數(shù):


第三個(gè)參數(shù) char* env() ,實(shí)際上存儲的就是當(dāng)前操作系統(tǒng)里的環(huán)境變量表。本質(zhì)是將環(huán)境變量表傳給進(jìn)程。

除了利用main函數(shù)的參數(shù)來獲取環(huán)境變量,我們還可以使用 getenv函數(shù):


getenv 是 C 語言中用于獲取環(huán)境變量值的標(biāo)準(zhǔn)庫函數(shù),接收環(huán)境變量名作為參數(shù),返回對應(yīng)的值;若變量不存在則返回 NULL,是程序訪問環(huán)境變量最簡便的接口。
現(xiàn)在就有一個(gè)問題,我我們在main函數(shù)里看到的 argv 和 env 兩個(gè)參數(shù),到底是誰傳遞過來的數(shù)據(jù)呢?實(shí)際上,進(jìn)程的命令行參數(shù)列表與環(huán)境變量列表,都是由其父進(jìn)程(通常為 bash 這類 Shell)在創(chuàng)建新進(jìn)程時(shí)傳遞的,而非由內(nèi)核直接生成。
因?yàn)槲覀冎疤岬竭^,我們運(yùn)行的所有文件、程序等等,其實(shí)都是 bash 這個(gè)進(jìn)程的子進(jìn)程,而作為子進(jìn)程我們可以獲取到父進(jìn)程(bash)的代碼和數(shù)據(jù)等等,所以bash會把會話的所有環(huán)境變量(如 PATH、HOME、USER)整理成 envp 數(shù)組,然后在創(chuàng)建新進(jìn)程的時(shí)候直接傳遞過去。這也間接的讓環(huán)境變量具有了全局性。
那么bash的這個(gè)環(huán)境變量列表又是從哪里獲取的呢?答案是:從Linux操作系統(tǒng)的配置文件信息里讀取到的。也就是說,當(dāng)我們啟動Linux操作系統(tǒng),也就是創(chuàng)建進(jìn)程bash的時(shí)候,會先讀取Linux的配置文件,然后把讀取到的信息加載到bash進(jìn)程的上下文數(shù)據(jù)里。這也是之所以我們只要重啟Linux操作系統(tǒng)之后,原先修改過的環(huán)境變量會被恢復(fù)成原來的值,重啟的本質(zhì)也就是重新再讀取加載一遍。

其中的 .bashrc 和 .bash_profile 就是要讀取的文件。



所以流程就是:bash創(chuàng)建時(shí)先會讀取 .bash_profile 文件,這個(gè)文件要執(zhí)行的操作是去訪問 .bashrc 這個(gè)文件,而 .bashrc 的文件操作是訪問 /etc/bashrc 這個(gè)系統(tǒng)文件,這個(gè)系統(tǒng)文件里面存在的就是環(huán)境變量信息。
我們還可以再驗(yàn)證一下:

先修改一下 .bash_profile 文件。

所以在最下面一行,我們登陸的時(shí)候,就會有對應(yīng)的提示信息。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
CentOS7服務(wù)器環(huán)境下vsftpd安裝及配置方法
這篇文章主要介紹了CentOS7服務(wù)器環(huán)境下vsftpd安裝及配置方法,結(jié)合實(shí)例形式分析了CentOS7服務(wù)器環(huán)境下進(jìn)行vsftpd安裝及配置的步驟與相關(guān)問題解決方法,需要的朋友可以參考下2018-03-03
Linux 中不輸入密碼運(yùn)行 sudo 命令的方法
sudo命令允許受信任的用戶作為另一個(gè)用戶運(yùn)行程序,默認(rèn)情況下是root用戶。這篇文章主要介紹了Linux 中不輸入密碼運(yùn)行 sudo 命令的方法,需要的朋友可以參考下2019-07-07
Linux模擬實(shí)現(xiàn)sleep函數(shù)
這篇文章主要為大家詳細(xì)介紹了Linux模擬實(shí)現(xiàn)sleep函數(shù),讓程序休眠一定的秒數(shù),到時(shí)間后自動恢復(fù)運(yùn)行2017-04-04
Apache Spark 2.0 在作業(yè)完成時(shí)卻花費(fèi)很長時(shí)間結(jié)束
大家在使用 Apache Spark 2.x 的時(shí)候可能會遇到這種現(xiàn)象:雖然我們的 Spark Jobs 已經(jīng)全部完成了,但是我們的程序卻還在執(zhí)行。怎么回事呢?下面小編通過實(shí)例代碼給大家介紹下2019-06-06
Linux進(jìn)程信號的捕捉&&信號補(bǔ)充內(nèi)容方式
信號處理在進(jìn)程從內(nèi)核態(tài)返回用戶態(tài)時(shí)觸發(fā),涉及狀態(tài)切換與權(quán)限管理,sigaction用于自定義信號處理,支持屏蔽信號,volatile確保變量內(nèi)存可見性,防止編譯器優(yōu)化導(dǎo)致的信號響應(yīng)異常2025-08-08
Ubuntu Server 14.04升級Ubuntu Server 16.04
這篇文章主要介紹了 Ubuntu Server 14.04升級Ubuntu Server 16.04,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2016-12-12

