命令行參數
我們知道,我們使用的指令它本質上也是一個程序,我們要執行這個指令,輸入指令名然后回車即可執行;但是對于指令帶選項,又是如何實現的呢?
問題:main
函數有沒有參數?
在我們之前寫代碼的時候,我們知道
main
函數是程序的入口;但是操作系統在執行程序之前,會先執行一個入口函數(_start
),然后由這個入口函數去調用我們的main
函數。那我們的
main
函數到底有沒有參數?答案是有的。
我們先來看下面運行程序的現象:
#include <stdio.h>
int main(int argc, char* argv[])
{for(int i = 0;i<argc;i++){printf("argv[%d] : %s\n",i,argv[i]);}return 0;
}
這里,我們在命令行中打開某個可執行程序,后面跟上選項(指令 -選項);
可以看到在
main
函數中我們是可以訪問命令行輸入的內容的(命令行參數)。那
main
函數的參數都有哪些內容呢?
argc
:命令行參數的個數argv
:命令行參數的內容(char*
類型的數組,最后以NULL
結尾)env
:環境變量表(在文章后面內容中詳細講解)。
在這里有一個疑問,我們在命令行輸入的內容是如何轉化成argv
表,并傳遞給main
函數的呢?
這個就比較簡單了,我們在命令行中輸入的內容,由我們的命令行解釋器
bash
對這些內容進行拆分,然后形成命令行參數表(argv
)和參數的個數argc
。然后再通過調用等一系列操作(
bash
創建子進程,通過execve
系統調用)將參數傳遞給main
函數。
簡單來說,就是命令行解釋器(bash
)對我們命令行內容進行拆分,然后形成命令行參數個數argc
和命令行參數列表argv
。
所以,有了命令行參數列表,我們程序就可以實現不同的子功能(命令 + 選項的實現原理)
環境變量
在了解環境變量之前,先思考一個問題,為什么在執行我們自己寫的程序時就要帶路徑,而使用指令程序時就不用帶路徑?
我們想要運行一個程序,首先要先找到這個程序(
bash
去找)這個問題就很簡單了,我們的指令程序都在
/usr/bin
目錄下,而我們的程序不在usr/bin
目錄下。但是,為什么在
usr/bin
路徑下的程序,在執行時不需要帶路徑?
- 環境變量一般指操作系統中用來指定操作系統運行環境的一些參數。
- 例如:我們在寫的
C/C++
代碼,在鏈接的時候,我們不知道所鏈接的動靜態庫在哪里,但是依然可以鏈接成功生成可執行程序,其原因就是:有關環境變量幫助編譯器進行查找。 - 環境變量通常具有某些特殊用途,在操作系統中通常具有全局性
查看環境變量
- 查看所有環境變量:
env
- 查看一個環境變量:
ench $環境變量名
設置環境變量
export
我們現在能夠看到環境變量了,我們可不可以修改環境變量?當然是可以的
export
新增環境變量
我們可以使用export
指令來新增一個新的環境變量,具體語法如下:
export name=val
export
除了新增一個環境變量,我們還可以使用它來修改一個已經存在的環境變量的值。
這里如果進行了上述修改,我們的大部分指令都無法使用了,因為在當前PATH
路徑下,bash
找不到可執行程序。
但是存在一些還可以使用的指令,因為這些指令是bash
進程自己執行的,比如export
。
在本篇文章后序內容詳細敘述
unset
我們可以新增一個環境變量,那我們可不可以刪除一個環境變量?當然也是可以的
unset
指令可以刪除一個環境變量,用法如下:
unset name
常見的環境變量
PATH
PATH
環境變量,它指的是命令的搜索路徑;
為什么在usr/bin
路徑下的程序,在執行時不需要帶路徑?
我們要運行一個程序,首先要找到它,所以我們自己寫的程序運行時需要帶路徑;
而在
usr/bin
路徑下的指令程序不需要帶路徑,這是因為存在環境變量PATH
幫助bash
去查找執行程序。
所以,當我們把我們自己寫的程序所在的路徑加入到PATH
中,或者將我們的可執行程序放到/usr/bin
目錄下,我們運行我們自己寫的程序就也不需要帶路徑了。
這里就不演示了,感興趣的可以去嘗試一下
HOME
在Linux
中,當我們執行cd ~
指令時,我們會進入當前用戶的家目錄;但是,操作系統是如何知道我們當前用戶的家目錄呢?
這里就直接說了:存在一個環境變量
HOME
;當我們執行cd ~
時,bash
就會在環境變量表中查找HOME
,然后進行到HOME
加目錄中。
此外,root
用戶的家目錄和普通用戶的家目錄還是存在一定差別的
SHELL
SHELL
環境變量,它表示當前的shell
,也就是當前使用的命令行解釋器;
一般情況下是/bin/bash
。
更多的環境變量
除了上述的環境變量,還存在非常多的環境變量,這里簡單了解一下
HOSTNAME
:當前系統的主機名HISTSIZE
:bash
記錄歷史指令的個數SSH_TTY
:當前通過SSH會話鏈接終端設備的路徑PWD
:表示當前路徑USER
:當前用戶的登錄名LOGNAME
:可以理解為和user
一樣_
:表示上次路徑
獲取環境變量
在上述中,講述了使用env
和echo $
查看環境變量,那我們現在想要通過寫代碼時獲取環境變量該如何去做呢?
main
函數參數
在上面敘述main
函數參數時,提到main
函數還存在第三個參數env
,我們就可以通過這個參數來獲取環境變量
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{int i = 0;for(;env[i]!=NULL;i++){printf("env[%d] : %s\n",i,env[i]);}return 0;
}
系統調用
main
函數第三個參數env
它是環境變量參數表,我們查看起來不是很方便;
我們可以通過系統調用來在代碼中獲取環境變量的值:
getenv
getenv
,我們把要查看環境變量的名字傳參給getenv
函數,它會返回我們查詢環境變量的值。
#include<stdio.h>
#include<stdlib.h>
int main()
{printf("%s\n",getenv("PATH"));return 0;
}
putenv
對于這個函數,這里就先不敘述,在后序文章中再詳細講解。
通過第三方變量獲取
在libc
在定義著一個全局變量environ
,它始終指向當前的環境變量表;
它不存在于任何頭文件,我們在使用它時,需要使用extern
聲明。
#include<stdio.h>
int main(int argc, char* argv[])
{extern char** environ;int i = 0;for(;environ[i]!=NULL;i++){printf("environ[%d] : %s\n",i,environ[i]);}
}
執行程序,我們可以發現依然可以獲取全部的環境變量。
此外,父進程的環境變量可以被子進程繼承;就比如父進程bash
創建我們的子進程時,
理解環境變量
要理解環境變量,這里我們先思考一個問題,環境變量存儲在哪里?
在執行一個程序時,首先要找到到這一個程序,那誰去找呢?
答案是bash
去找,通過環境變量PATH
去找,在bash
中存儲著一份環境變量表;
現在又存在一個問題,當我們修改環境變量以后,退出登錄,再次登錄時我們會發現環境變量又變為修改前的值了。
所以環境變量最開始是存儲在哪里呢?
答案:在系統的配置文件中。
那我們現在是不是就可以這樣去理解了:在我們每次登錄時,操作系統為我們創建一個bash
,再將環境變量表拷貝一份到bash
中;這樣我們每次登錄bash
中都存在一份環境變量表。
環境變量特性
- 環境變量通常具有全局屬性,可以被子進程繼承下去。
環境變量表
在上訴代碼中,我們無論是使用main
函數參數env
還是全局指針變量environ
進行訪問全局變量是時,循環條件寫的都是env[i]!=NULL
/environ[i]!=NULL
;
這是因為,環境變量表它本質上就是一個指針數組,數組最后以NULL
結尾。
補充
本地變量
在操作系統中除了環境變量之外,還存在著本地變量;
就比如我們在命令行直接輸入i=1
,這樣我們使用env
查看環境變量時是查看不到i
的;但是我們可以使用echo $i
來查看變量i
的值。
env
是查看所有的環境變量,而如果我們想要查看所有的本地變量,就要使用set
,它能顯示出所有的環境變量和本地變量;當然我們也可以使用echo $
查看某一個變量的值。
這里可能感覺怪怪的,為什么要存在本地變量呢?
- 作用域限制
本地變量僅在當前Shell會話或函數內部有效,不會傳遞給子進程或其他Shell環境。這種隔離性避免了變量被意外修改或污染其他進程的運行環境。- 臨時數據存儲
適用于臨時存儲中間計算結果或循環控制變量(如計數器),用完即棄,無需長期保留,簡化資源管理。- 安全性增強
若變量包含敏感信息(如臨時密鑰),使用本地變量可防止其被子進程繼承,降低數據泄露風險。- 避免命名沖突
在腳本或函數中使用本地變量(如通過local
關鍵字聲明),能隔離同名變量的影響,提升代碼的模塊化和可維護性。
以博主現在的認知,簡單理解就是為了滿足bash
的語法
內建命令
這個問題在上面簡單描述了,我們的環境變量是存在于bash
中的,因為我們所有執行的程序都是bash
去執行的,bash
需要這些環境變量來完成執行我們的程序;
在修改PATH
時,我們發現一個問題,將PATH
修改之后,一部分指令不能執行了,但是一部分指令是可以執行的,這是為什么呢?
這里簡單解釋一下:
我們可以將指令分為兩部分:
- 普通命令:
bash
通過創建子進程,然后讓子進程去執行;- 內建命令:
bash
自己通過函數調用或者系統調用去完成,不需要創建子進程。
這里內建命令像export
就是bash
自己直接去完成的,我們就是修改了PATH
對它是沒有影響的,所以它可以執行;
到這里本篇文章內容大致就結束了,感謝支持
簡單總結:
- 了解命令行參數,理解
main
函數是三個參數- 環境變量,查看
env/echo
、設置環境變量export
- 了解常見的環境變量
- 通過
main
函數參數、系統調用、environ
獲取環境變量- 理解環境變量具有全局性、環境變量表的結構
- 簡單了解本地變量和內建命令