什么是環境變量?
如下,在shell中定義一個變量,這個變量會被這個shell的子shell或者當前這個shell的進程所繼承。
首先,在當前的shell中定義了一個HOLIDAY變量,定義變量用key=value
的形式,等號兩邊不可有空格,key
常用大寫,value
可以選用引號括起來,但如果value
中有空格或者特殊字符時一定要用引號。
[dpc@aliyun ~]$ HOLIDAY=happy
[dpc@aliyun ~]$ echo $HOLIDAY
happy
進入子shell,查看HOLIDAY
的值,發現子shell中沒有這個變量
[dpc@aliyun ~]$ sh
sh-4.2$ echo $HOLIDAY
退出子shell,回到原來的shell查看變量是存在的。
sh-4.2$ exit
exit
[dpc@aliyun ~]$ echo $HOLIDAY
happy
用export
將變量聲明到所有的shell中,重新進入子shell,查看是否有變量HOLIDAY
。
[dpc@aliyun ~]$ export HOLIDAY
[dpc@aliyun ~]$ sh
sh-4.2$ echo $HOLIDAY
happy
現在我們可以看到HOLIDAY
變量的值可以被打印。因為現在HOLIDAY
已經成為環境變量(Environment variables),這個環境變量在當前shell中定義,並被所有子shell和進程繼承。在被export
之前,HOLIDAY
變量只是一個shell變量,不是環境變量,其只在當前的shell下有效。其實shell變量就是一個局部變量,環境變量就是一個全局變量,直接聲明的是一個局部變量,通過export
命令聲明的是一個全局變量。
如果要查看環境變量,可以使用printenv
、env
、set
這三個命令,前兩個命令是等效的。
[dpc@aliyun ~]$ printenv
XDG_SESSION_ID=19590
HOSTNAME=aliyun
SHELL=/bin/bash
TERM=xterm
HISTSIZE=1000
SSH_CLIENT=113.87.184.183 3761 22
HOLIDAY=happy
SSH_TTY=/dev/pts/0
USER=dpc
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
MAIL=/var/spool/mail/root
PWD=/home/dpc
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
HOME=/home/dpc
SHLVL=2
LOGNAME=dpc
SSH_CONNECTION=113.87.186.183 3761 172.18.4.152 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/printenv
OLDPWD=/root
printenv
、env
、set
的區別:
-
printenv
可用於查看單個環境變量,此時和用echo
查看環境變量是等效的[dpc@aliyun ~]$ printenv SHELL /bin/bash [dpc@aliyun ~]$ echo $SHELL /bin/bash
-
env
可用於修改變量,printenv
與env
查看的環境變量是一樣的 -
set
可查看所有的shell變量[dpc@aliyun ~]$ printenv | wc -l 23 [dpc@aliyun ~]$ env | wc -l 23 [dpc@aliyun ~]$ set | wc -l 57
一些常見的環境變量:
SHELL
:用於解釋當前輸入的命令的shell,通常默認是bash,另一種常見的是sh
TERM
:當前運行的終端類型,常見是xterm
USER
:當前登錄的用戶
PWD
:當前的工作目錄
OLDPWD
:前一次的工作目錄,此變量用於使用cd -
命令切換到前一次的工作目錄
LS_COLORS
:定義了ls
命令輸出的不同類型文件顯示的顏色
MAIL
:當前用戶郵箱的路徑
PATH
:系統查找命令時的目錄列表。當用戶輸入一個命令時,系統按順序從該列表中的目錄查找可執行的命令
LANG
:當前的語言和本地化設置,通常是系統語言和字符編碼
HOME
:當前用戶的家目錄,root用戶為/root
,其它用戶為/home/username
_
:前一次執行的命令
除了環境變量,還有一些常見的shell變量。注意shell變量用echo $variable_name
查看
BASHOPTS
:當前bash被執行時使用的選項列表BASH_VERSION
:當前bash的版本BASH_VERSINFO
:當前bash的版本COLUMNS
:當前窗口用於打印輸出的列數,改變終端窗口大小列數隨之變化DIRSTACK
:當前pushd
和popd
命令可用的目錄堆棧HISTFILESIZE
:可存儲到文件的中最大歷史命令行數HISTSIZE
:可存儲到內存中的最大歷史命令行數HOSTNAME
:本機的hostnameIFS
:內部字段分隔符(Internal Field Separator),用於分隔命令行中的輸入,默認是空格PS1
:主要的命令提示符,定義了啟動一個shell會話時的每行開頭的提示符。PS2
用於定義當一個命令跨多行時進行輔助聲明的提示符。SHELLOPTS
:可以用set
命令設置的shell選項UID
:當前用戶的UID
設置和取消變量
將環境變量降為shell變量
[dpc@aliyun ~]$ export -n HOLIDAY
此時HOLIDAY
將不再為環境變量
[dpc@aliyun ~]$ printenv HOLIDAY
但是它仍為shell變量
[dpc@aliyun ~]$ set | grep HOLIDAY
HOLIDAY=happy
如果想完全取消變量,把環境變量和shell變量都取消掉,可以使用unset
命令
[dpc@aliyun ~]$ unset HOLIDAY
可驗證此時HOLIDAY
變量已經不存在了
[dpc@aliyun ~]$ echo $HOLIDAY
登錄shell與非登錄shell
當我們啟動一個shell時它會去讀取配置文件,但是在不同的啟動方式下,它讀取的配置文文件也不同。
shell會話有四個概念:
- 交互式(Interactive)
- 非交互式(Non-Interactive)
- 登錄(Login)
- 非登錄(Non-Login)
交互式和非交互式好理解,我們在有GUI(圖形界面)的linux的終端上輸入命令或者通過xshell連接服務器后輸入命令都是在交互式shell會話中執行。而我們在終端中運行某個shell腳本,此時這個shell腳本是在非交互式shell會話中執行的。由此也可知,一個終端會話可以是這兩種的結合。
對於交互式shell和非交互式shell,它們的類型不影響我們執行命令時使用的環境變量。
對於登錄(Login)和非登錄(Non-Login),兩者比較讓人迷惑。
比如我們通過ssh登錄一個需要驗證的遠程服務器時,我們此時的shell會話就是一個登錄shell會話。
[dpc@aliyun ~]$ ssh root@120.77.1.1
root@120.77.1.1's password:
在我們輸入密碼后,登錄到了shell,此時由登錄shell進入了非登錄shell。
登錄shell就是我們還沒有輸入密碼登錄到這個shell,當進入非登錄shell時,意味着我們已經驗證過了當前用戶的密碼登錄到了該用戶的shell中。
最簡單的判斷登錄還是非登錄shell的方法是:在當前的shell中,輸入echo $0
, 查看結果。非登錄shell的輸出是bash
或su
,登錄shell的輸出是-bash
或-su
。
[root@aliyun ~]# echo $0
-bash
[root@aliyun ~]# su dpc
[dpc@aliyun root]$ echo $0
bash
[dpc@aliyun root]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
上面我們首先以root
用戶登錄了shell,此時為登錄shell。然后切換到了dpc
用戶,此時為非登錄shell,我們查看非登錄shell時的環境變量,使用的仍然是root
用戶的環境變量。
再試下下面的一種情況
[root@aliyun ~]# su - dpc
Last login: Thu Sep 24 00:23:07 CST 2020 on pts/0
[dpc@aliyun ~]$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dpc/.local/bin:/home/dpc/bin
我們會發現用su dpc
切換用戶時沒有驗證密碼,進入了登錄shell,使用的是原來的root用戶的環境變量;用su - dpc
切換用戶時驗證了密碼,進入了非登錄shell,使用的是dpc用戶的環境變量。
以下三個命令是等效的,都可以進入非登錄shell。
su - dpc
su -l dpc
su --login dpc
登錄shell和非登錄shell的環境變量有何不同呢?
登錄shell執行腳本的順序
- 登錄shell執行
/etc/profile
/etc/profile
執行/etc/profile.d
目錄下的腳本- 然后執行當前用戶的
~/.bash_profile
~/.bash_profile
執行當前用戶的~/.bashrc
~/.bashrc
執行/etc/bashrc
非登錄shell執行腳本的順序
- 非登錄shell首先執行
~/.bashrc
- 然后
~/.bashrc
執行/etc/bashrc
/etc/bashrc
調用/etc/profile.d
目錄下的腳本
參考
[1] environment and shell
[3] Linxu環境變量
[4] System Variables
[5] Difference Between Login Shell and Non-Login Shell
[6] Login Shell Non-Login Shell
[7] Interactive and non-interactive shell
[8] How To Read and Set Environmental and Shell Variables on a Linux VPS