5. 理解 shell
5.1 shell 的類型
系統啓動什麼樣的shell程序取決於個人的用戶 ID 配置。在 /etc/passwd 文件中,在用戶 ID 記錄的第 7 個字段中列出了默認的 shell 程序。只要用戶
登錄到某個虛擬控制檯終端或是在 GUI 中啓動終端仿真器,默認的 shell 程序就會開始運行。
[devalone@devalone shell-script]$ cat /etc/passwd | grep devalone
devalone:x:1000:1000:MichaelY.:/home/devalone:/bin/bash
bash shell 程序位於 /bin 目錄內。從長列表中可以看出 /bin/bash(bash shell)是一個可執行程序:
[devalone@devalone shell-script]$ ls -lF /bin/bash
-rwxr-xr-x. 1 root root 1071984 9月 30 2016 /bin/bash*
默認的交互shell會在用戶登錄某個虛擬控制檯終端或在GUI中運行終端仿真器時啓動。不過還有另外一個默認 shell 是 /bin/sh,它作爲默認的系統 shell,
用於那些需要在啓動時使用的系統 shell腳本。
系統中可用的 shell 列於 /etc/shells 文件中,可以查看該文件瞭解可用 shell:
[devalone@devalone shell-script]$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
5.2 shell 的父子關係
-----------------------------------------------------------------------------------------------------------------------------------------
用於登錄某個虛擬控制器終端或在GUI中運行終端仿真器時所啓動的默認的交互shell,是一個父 shell。
在CLI提示符後輸入 /bin/bash 命令或其他等效的 bash 命令時,會創建一個新的 shell 進程。這個 shell 進程被稱爲子 shell(child shell)。子shell
也擁有 CLI 提示符,同樣會等待命令輸入。
當輸入bash、生成子shell的時候,看不到任何相關的信息。使用 ps 命令配合 -f 選項查看:
[devalone@devalone shell-script]$ ps -f
UID PID PPID C STIME TTY TIME CMD
devalone 2373 2360 0 10:17 pts/1 00:00:00 -bash
devalone 3839 2373 0 15:53 pts/1 00:00:00 ps -f
[devalone@devalone shell-script]$ bash
[devalone@devalone shell-script]$ ps -f
UID PID PPID C STIME TTY TIME CMD
devalone 2373 2360 0 10:17 pts/1 00:00:00 -bash
devalone 3840 2373 1 15:54 pts/1 00:00:00 bash
devalone 3872 3840 0 15:54 pts/1 00:00:00 ps -f
第一次使用ps -f的時候,顯示出了兩個進程。
輸入命令bash之後,一個子shell 就出現了。第二個 ps -f 是在子shell 中執行的。可以從顯示結果中看到有兩個 bash shell 程序在運行。第一個
bash shell 程序,也就是父shell進程,其原始進程ID是 2373。第二個 bash shell程序,即子shell進程,其PID是 3840。注意,子shell 的父進程 ID
(PPID)是 2373,指明瞭這個父shell 進程就是該子shell 的父進程。
可以利用 exit 命令退出子shell。
5.2.1 進程列表
-----------------------------------------------------------------------------------------------------------------------------------------
可以在一行中指定要依次運行的一系列命令。這可以通過命令列表來實現,只需要在命令之間加入分號(;) 即可。
[devalone@devalone ~]$ pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls
在上面的例子中,所有的命令依次執行,不存在任何問題。不過這並不是進程列表。命令列表要想成爲進程列表,這些命令必須包含在括號裏。
[devalone@devalone ~]$ (pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls)
儘管多出來的括號看起來沒有什麼太大的不同,但起到的效果確是非同尋常。括號的加入使命令列表變成了進程列表,生成了一個子shell來執行對應的命令。
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
進程列表是一種命令分組 (command grouping)。另一種命令分組是將命令放入花括號中,並在命令列表尾部加上分號 (;)。語法爲 { command; }。使用
花括號進行命令分組並不會像進程列表那樣創建出子 shell。
要想知道是否生成了子 shell,得藉助一個使用了環境變量的命令。這個命令就是 echo $BASH_SUBSHELL。如果該命令返回 0,就表明沒有子 shell。如果返
回 1 或者其他更大的數字,就表明存在子 shell。
[devalone@devalone ~]$ pwd ; cd /etc ; pwd ; cd ; pwd ; echo $BASH_SUBSHELL
/home/devalone
/etc
/home/devalone
0
[devalone@devalone ~]$ (pwd ; cd /etc ; pwd ; cd ; pwd ; echo $BASH_SUBSHELL)
/home/devalone
/etc
/home/devalone
1
甚至可以在命令列表中嵌套括號來創建子 shell 的子 shell。
[devalone@devalone ~]$ (pwd;echo $BASH_SUBSHELL)
/home/devalone
1
[devalone@devalone ~]$ (pwd;(echo $BASH_SUBSHELL))
/home/devalone
2
在 shell 腳本中,經常使用子 shell 進行多進程處理。但是採用子 shell 的成本不菲,會明顯拖慢處理速度。在交互式的 CLI shell 會話中,子 shell
同樣存在問題。它並非真正的多進程處理,因爲終端控制着子 shell 的 I/O。
5.2.2 shell 的其它用法
-----------------------------------------------------------------------------------------------------------------------------------------
在交互式的 shell CLI中,還有很多更富有成效的子 shell用法。進程列表、協程和管道都利用了子 shell。它們都可以有效地在交互式 shell 中使用。
● 後臺模式
-------------------------------------------------------------------------------------------------------------------------------------
在後臺模式中運行命令可以在處理命令的同時讓出CLI,以供他用。
要想將命令置入後臺模式,可以在命令末尾加上字符&
[devalone@devalone ~]$ sleep 3000&
[1] 1829
[devalone@devalone ~]$ ps -f
UID PID PPID C STIME TTY TIME CMD
devalone 1742 1741 0 17:35 pts/0 00:00:00 -bash
devalone 1829 1742 0 17:57 pts/0 00:00:00 sleep 3000
devalone 1830 1742 0 17:58 pts/0 00:00:00 ps -f
sleep 命令會在後臺(&) 睡眠3000秒 (50分鐘)。當它被置入後臺,在 shell CLI 提示符返回之前,會出現兩條信息。第一條信息是顯示在方括號中的
後臺作業(background job)號 (1)。第二條是後臺作業的進程ID(1829)。
也可以使用 jobs 命令來顯示後臺作業信息。jobs 命令可以顯示出當前運行在後臺模式中的所有用戶的進程(作業)。
[devalone@devalone ~]$ jobs
[1]+ 運行中 sleep 3000 &
jobs命令在方括號中顯示出作業號(1)。它還顯示了作業的當前狀態(running) 以及對應的命令 (sleep 3000 &)。
利用 jobs 命令的 -l(字母 L 的小寫形式)選項,還能夠看到更多的相關信息。除了默認信息之外,-l 選項還能夠顯示出命令的 PID。
[devalone@devalone ~]$ jobs -l
[1]+ 1829 運行中 sleep 3000 &
一旦後臺作業完成,就會顯示出結束狀態:
[1]+ Done sleep 3000 &
● 將進程列表置入後臺
-------------------------------------------------------------------------------------------------------------------------------------
進程列表是運行在子 shell 中的一條或多條命令。使用包含了sleep 命令的進程列表,並顯示出變量 BASH_SUBSHELL,結果和期望的一樣。
[devalone@devalone ~]$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)
1
將相同的進程列表置入後臺模式會在命令輸出上表現出些許不同:
[devalone@devalone ~]$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2) &
[2] 1861
[devalone@devalone ~]$ 1
[2]+ 已完成 ( sleep 2; echo $BASH_SUBSHELL; sleep 2 )
把進程列表置入後臺會產生一個作業號和進程 ID,然後返回到提示符。不過奇怪的是表明單一級子 shell 的數字 1 顯示在了提示符的旁邊!只需要按
一下回車鍵,就會得到另一個提示符。
在 CLI 中運用子 shell 的創造性方法之一就是將進程列表置入後臺模式。既可以在子 shell 中進行繁重的處理工作,同時也不會讓子 shell 的I/O
受制於終端。
● 協程(coproc)
-------------------------------------------------------------------------------------------------------------------------------------
協程可以同時做兩件事。它在後臺生成一個子shell,並在這個子 shell中執行命令。
要進行協程處理,得使用 coproc 命令,還有要在子 shell 中執行的命令。
[devalone@devalone ~]$ coproc sleep 10
[2] 1870
除了會創建子 shell 之外,協程基本上就是將命令置入後臺模式。當輸入 coproc 命令及其參數之後,會發現啓用了一個後臺作業。屏幕上會顯示出
後臺作業號(1)以及進程ID(1870)
jobs命令能夠顯示出協程的處理狀態。
[devalone@devalone ~]$ jobs
[1]- 運行中 sleep 3000 &
[2]+ 運行中 coproc COPROC sleep 10 &
上面的例子中可以看到在子 shell 中執行的後臺命令是 coproc COPROC sleep 10。COPROC 是 coproc 命令給進程起的名字。可以使用命令的擴展語法
自己設置這個名字:
[devalone@devalone ~]$ coproc My_Job { sleep 10; }
通過使用擴展語法,協程的名字被設置成 My_Job。這裏要注意的是,擴展語法寫起來有點麻煩。必須確保在第一個花括號 ({) 和命令名之間有一個空格。
還必須保證命令以分號(;)結尾。另外,分號和閉花括號(})之間也得有一個空格。
將協程與進程列表結合起來產生嵌套的子 shell。只需要輸入進程列表,然後把命令 coproc 放在前面就行了。
[devalone@devalone ~]$ coproc ( sleep 10; sleep 2 )
[2] 1883
5.3 理解shell 的內建命令
-----------------------------------------------------------------------------------------------------------------------------------------
內建命令和非內建命令的操作方式大不相同。
5.3.1 外部命令
-----------------------------------------------------------------------------------------------------------------------------------------
外部命令,有時候也被稱爲文件系統命令,是存在於 bash shell之外的程序。它們並不是 shell 程序的一部分。外部命令程序通常位於/bin、/usr/bin、
/sbin 或 /usr/sbin中。
ps 就是一個外部命令。可以使用 which 和 type 命令找到它。
[devalone@devalone ~]$ which ps
/usr/bin/ps
[devalone@devalone ~]$ type -a ps
ps 是 /usr/bin/ps
當外部命令執行時,會創建出一個子進程。這種操作被稱爲衍生(forking)。外部命令 ps 很方便顯示出它的父進程以及自己所對應的衍生子進程。
[devalone@devalone ~]$ ps -f
UID PID PPID C STIME TTY TIME CMD
devalone 1742 1741 0 17:35 pts/0 00:00:00 -bash
devalone 1829 1742 0 17:57 pts/0 00:00:00 sleep 3000
devalone 1908 1742 0 18:32 pts/0 00:00:00 ps -f
作爲外部命令,ps 命令執行時會創建出一個子進程。在這裏,ps命令的 PID是 1908,父 PID 是 1742。作爲父進程的 bash shell 的 PID 是 1742。
當進程必須執行衍生操作時,它需要花費時間和精力來設置新子進程的環境。所以說,外部命令多少還是有代價的。
5.3.2 內建命令
-----------------------------------------------------------------------------------------------------------------------------------------
內建命令和外部命令的區別在於前者不需要使用子進程來執行。它們已經和 shell 編譯成了一體,作爲 shell 工具的組成部分存在。不需要藉助外部程序
文件來運行。
cd 和 exit 命令都內建於 bash shell。可以利用 type 命令來了解某個命令是否是內建的。
[devalone@devalone ~]$ type cd
cd 是 shell 內建
[devalone@devalone ~]$ type exit
exit 是 shell 內建
因爲既不需要通過衍生出子進程來執行,也不需要打開程序文件,內建命令的執行速度要更快,效率也更高。
要注意,有些命令有多種實現。例如 echo 和 pwd 既有內建命令也有外部命令。兩種實現略有不同。要查看命令的不同實現,使用 type 命令的-a選項。
[devalone@devalone ~]$ type -a echo
echo 是 shell 內建
echo 是 /usr/bin/echo
[devalone@devalone ~]$ which echo
/usr/bin/echo
[devalone@devalone ~]$ type -a pwd
pwd 是 shell 內建
pwd 是 /usr/bin/pwd
[devalone@devalone ~]$ which pwd
/usr/bin/pwd
命令 type -a 顯示出了每個命令的兩種實現。注意,which 命令只顯示出了外部命令文件。
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
對於有多種實現的命令,如果想要使用其外部命令實現,直接指明對應的文件就可以了。例如,要使用外部命令 pwd,可以輸入 /usr/bin/pwd。
● history 命令
-------------------------------------------------------------------------------------------------------------------------------------
一個有用的內建命令是 history 命令。bash shell 會跟蹤用過的命令。用戶可以喚回這些命令並重新使用。
[devalone@devalone ~]$ history
1020 (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2) &
1021 coproc sleep 10
1022 jobs
1023 coproc sleep 10
1024 jobs
1025 coproc My_Job { sleep 10; }
1026 jobs
1027 coproc ( sleep 10; sleep 2 )
1028 jobs
1029 ps --forest
...
通常歷史記錄中會保存最近的 1000 條命令。
可以喚回並重用歷史列表中最近的命令。這樣能夠節省時間和擊鍵量。輸入!!,然後按回車鍵就能夠喚出剛剛用過的那條命令來使用。
[devalone@devalone ~]$ ps --forest
PID TTY TIME CMD
1742 pts/0 00:00:00 bash
1829 pts/0 00:00:00 \_ sleep
1934 pts/0 00:00:00 \_ ps
[devalone@devalone ~]$ !!
ps --forest
PID TTY TIME CMD
1742 pts/0 00:00:00 bash
1829 pts/0 00:00:00 \_ sleep
1935 pts/0 00:00:00 \_ ps
命令歷史記錄被保存在隱藏文件 .bash_history 中,它位於用戶的主目錄中。這裏要注意的是,bash命令的歷史記錄是先存放在內存中,當 shell 退出時
才被寫入到歷史文件中。
[devalone@devalone ~]$ cat .bash_history
grep [du] testfile
ll
gzip testfile
ll
rm ln_test
ll
ll testfile*
gunzip testfile.gz
ll
...
可以在退出 shell 會話之前強制將命令歷史記錄寫入 .bash_history 文件。要實現強制寫入,需要使用 history 命令的 -a 選項。
[devalone@devalone ~]$ history -a
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
要強制重新讀取 .bash_history 文件,更新終端會話的歷史記錄,可以使用 history -n 命令。
可以喚回歷史列表中任意一條命令。只需輸入驚歎號和命令在歷史列表中的編號即可。
[devalone@devalone ~]$ history
...
1040 history
1041 history | less
1042 ps --forest
1043 cat .bash_history
1044 man history
1045 history -a
1046 history
[devalone@devalone ~]$ !1042
ps --forest
PID TTY TIME CMD
1742 pts/0 00:00:00 bash
1973 pts/0 00:00:00 \_ ps
● 命令別名
-------------------------------------------------------------------------------------------------------------------------------------
alias 命令是另一個 shell 的內建命令。命令別名允許爲常用的命令(及其參數)創建另一個名稱,從而將輸入量減少到最低。
要查看當前可用的別名,使用 alias 命令以及選項 -p。
[devalone@devalone ~]$ alias -p
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias vi='vim'
注意 ll 是 'ls -l --color=auto' 命令的別名。
可以使用 alias 命令創建屬於自己的別名:
[devalone@devalone ~]$ alias lii='ls -li'
[devalone@devalone shell_test]$ lii
總用量 16
3021080 drwxrwxr-x. 2 devalone devalone 4096 7月 3 10:46 new_dir
2892886 -rw-rw-r--. 1 devalone devalone 23 7月 3 14:29 sortfile
2892883 -rwxrwxr-x. 1 devalone devalone 152 7月 3 10:51 test1.sh
2892882 -rw-rw-r--. 1 devalone devalone 277 7月 3 11:26 testfile
在定義好別名之後,隨時都可以在 shell 中使用它,就算在 shell 腳本中也沒問題。要注意,因爲命令別名屬於內部命令,一個別名僅在它所被定義的
shell 進程中才有效。
5.3.3 bash shell 命令彙總
-----------------------------------------------------------------------------------------------------------------------------------------
bash 內建命令
+-----------+------------------------------------------------------------------------------------------
| 命 令 | 描 述
+-----------+------------------------------------------------------------------------------------------
| : | 擴展參數列表,執行重定向操作
+-----------+------------------------------------------------------------------------------------------
| . | 讀取並執行指定文件中的命令(在當前shell環境中)
+-----------+------------------------------------------------------------------------------------------
| alias | 爲指定命令定義一個別名
+-----------+------------------------------------------------------------------------------------------
| bg | 將作業以後臺模式運行
+-----------+------------------------------------------------------------------------------------------
| bind | 將鍵盤序列綁定到一個readline函數或宏
+-----------+------------------------------------------------------------------------------------------
| break | 退出for、while、select或until循環
+-----------+------------------------------------------------------------------------------------------
| builtin | 執行指定的shell內建命令
+-----------+------------------------------------------------------------------------------------------
| caller | 返回活動子函數調用的上下文
+-----------+------------------------------------------------------------------------------------------
| cd | 將當前目錄切換爲指定的目錄
+-----------+------------------------------------------------------------------------------------------
| command | 執行指定的命令,無需進行通常的shell查找
+-----------+------------------------------------------------------------------------------------------
| compgen | 爲指定單詞生成可能的補全匹配
+-----------+------------------------------------------------------------------------------------------
| complete | 顯示指定的單詞是如何補全的
+-----------+------------------------------------------------------------------------------------------
| compopt | 修改指定單詞的補全選項
+-----------+------------------------------------------------------------------------------------------
| continue | 繼續執行for、while、select或until循環的下一次迭代
+-----------+------------------------------------------------------------------------------------------
| declare | 聲明一個變量或變量類型。
+-----------+------------------------------------------------------------------------------------------
| dirs | 顯示當前存儲目錄的列表
+-----------+------------------------------------------------------------------------------------------
| disown | 從進程作業表中刪除指定的作業
+-----------+------------------------------------------------------------------------------------------
| echo | 將指定字符串輸出到STDOUT
+-----------+------------------------------------------------------------------------------------------
| enable | 啓用或禁用指定的內建shell命令
+-----------+------------------------------------------------------------------------------------------
| eval | 將指定的參數拼接成一個命令,然後執行該命令
+-----------+------------------------------------------------------------------------------------------
| exec | 用指定命令替換shell進程
+-----------+------------------------------------------------------------------------------------------
| exit | 強制shell以指定的退出狀態碼退出
+-----------+------------------------------------------------------------------------------------------
| export | 設置子shell進程可用的變量
+-----------+------------------------------------------------------------------------------------------
| fc | 從歷史記錄中選擇命令列表
+-----------+------------------------------------------------------------------------------------------
| fg | 將作業以前臺模式運行
+-----------+------------------------------------------------------------------------------------------
| getopts | 分析指定的位置參數
+-----------+------------------------------------------------------------------------------------------
| hash | 查找並記住指定命令的全路徑名
+-----------+------------------------------------------------------------------------------------------
| help | 顯示幫助文件
+-----------+------------------------------------------------------------------------------------------
| history | 顯示命令歷史記錄
+-----------+------------------------------------------------------------------------------------------
| jobs | 列出活動作業
+-----------+------------------------------------------------------------------------------------------
| kill | 向指定的進程ID(PID)發送一個系統信號
+-----------+------------------------------------------------------------------------------------------
| let | 計算一個數學表達式中的每個參數
+-----------+------------------------------------------------------------------------------------------
| local | 在函數中創建一個作用域受限的變量
+-----------+------------------------------------------------------------------------------------------
| logout | 退出登錄shell
+-----------+------------------------------------------------------------------------------------------
| mapfile | 從STDIN讀取數據行,並將其加入索引數組
+-----------+------------------------------------------------------------------------------------------
| popd | 從目錄棧中刪除記錄
+-----------+------------------------------------------------------------------------------------------
| printf | 使用格式化字符串顯示文本
+-----------+------------------------------------------------------------------------------------------
| pushd | 向目錄棧添加一個目錄
+-----------+------------------------------------------------------------------------------------------
| pwd | 顯示當前工作目錄的路徑名
+-----------+------------------------------------------------------------------------------------------
| read | 從STDIN讀取一行數據並將其賦給一個變量
+-----------+------------------------------------------------------------------------------------------
| readarray | 從STDIN讀取數據行並將其放入索引數組
+-----------+------------------------------------------------------------------------------------------
| readonly | 從STDIN讀取一行數據並將其賦給一個不可修改的變量
+-----------+------------------------------------------------------------------------------------------
| return | 強制函數以某個值退出,這個值可以被調用腳本提取
+-----------+------------------------------------------------------------------------------------------
| set | 設置並顯示環境變量的值和shell屬性
+-----------+------------------------------------------------------------------------------------------
| shift | 將位置參數依次向下降一個位置
+-----------+------------------------------------------------------------------------------------------
| shopt | 打開/關閉控制shell可選行爲的變量值
+-----------+------------------------------------------------------------------------------------------
| source | 讀取並執行指定文件中的命令(在當前shell環境中)
+-----------+------------------------------------------------------------------------------------------
| suspend | 暫停shell的執行,直到收到一個SIGCONT信號
+-----------+------------------------------------------------------------------------------------------
| test | 基於指定條件返回退出狀態碼0或1
+-----------+------------------------------------------------------------------------------------------
| times | 顯示累計的用戶和系統時間
+-----------+------------------------------------------------------------------------------------------
| trap | 如果收到了指定的系統信號,執行指定的命令
+-----------+------------------------------------------------------------------------------------------
| type | 顯示指定的單詞如果作爲命令將會如何被解釋
+-----------+------------------------------------------------------------------------------------------
| typeset | 聲明一個變量或變量類型。
+-----------+------------------------------------------------------------------------------------------
| ulimit | 爲系統用戶設置指定的資源的上限
+-----------+------------------------------------------------------------------------------------------
| umask | 爲新建的文件和目錄設置默認權限
+-----------+------------------------------------------------------------------------------------------
| unalias | 刪除指定的別名
+-----------+------------------------------------------------------------------------------------------
| unset | 刪除指定的環境變量或shell屬性
+-----------+------------------------------------------------------------------------------------------
| wait | 等待指定的進程完成,並返回退出狀態碼
+-----------+------------------------------------------------------------------------------------------
bash shell 常見外部命令
+-----------------------------------------------------------------------------------------------------
| 命 令 | 描 述
+-----------+------------------------------------------------------------------------------------------
| bzip2 | 採用Burrows-Wheeler塊排序文本壓縮算法和霍夫曼編碼進行壓縮
+-----------+------------------------------------------------------------------------------------------
| cat | 列出指定文件的內容
+-----------+------------------------------------------------------------------------------------------
| chage | 修改指定系統用戶賬戶的密碼過期日期
+-----------+------------------------------------------------------------------------------------------
| chfn | 修改指定用戶賬戶的備註信息
+-----------+------------------------------------------------------------------------------------------
| chgrp | 修改指定文件或目錄的默認屬組
+-----------+------------------------------------------------------------------------------------------
| chmod | 爲指定文件或目錄修改系統安全權限
+-----------+------------------------------------------------------------------------------------------
| chown | 修改指定文件或目錄的默認屬主
+-----------+------------------------------------------------------------------------------------------
| chpasswd | 讀取一個包含登錄名/密碼的文件並更新密碼
+-----------+------------------------------------------------------------------------------------------
| chsh | 修改指定用戶賬戶的默認shell
+-----------+------------------------------------------------------------------------------------------
| clear | 從終端仿真器或虛擬控制檯終端刪除文本
+-----------+------------------------------------------------------------------------------------------
| compress | 最初的Unix文件壓縮工具
+-----------+------------------------------------------------------------------------------------------
| coproc | 在後臺模式中生成子shell,並執行指定的命令
+-----------+------------------------------------------------------------------------------------------
| cp | 將指定文件複製到另一個位置
+-----------+------------------------------------------------------------------------------------------
| crontab | 初始化用戶的crontable文件對應的編輯器(如果允許的話)
+-----------+------------------------------------------------------------------------------------------
| cut | 刪除文件行中指定的位置
+-----------+------------------------------------------------------------------------------------------
| date | 以各種格式顯示日期
+-----------+------------------------------------------------------------------------------------------
| df | 顯示所有掛載設備的當前磁盤空間使用情況
+-----------+------------------------------------------------------------------------------------------
| du | 顯示指定文件路徑的磁盤使用情況
+-----------+------------------------------------------------------------------------------------------
| emacs | 調用emacs文本編輯器
+-----------+------------------------------------------------------------------------------------------
| file | 查看指定文件的文件類型
+-----------+------------------------------------------------------------------------------------------
| find | 對文件進行遞歸查找
+-----------+------------------------------------------------------------------------------------------
| free | 查看系統上可用的和已用的內存
+-----------+------------------------------------------------------------------------------------------
| gawk | 使用編程語言命令的流編輯器
+-----------+------------------------------------------------------------------------------------------
| grep | 在文件中查找指定的文本字符串
+-----------+------------------------------------------------------------------------------------------
| gedit | 調用GNOME桌面編輯器
+-----------+------------------------------------------------------------------------------------------
| getopt | 解析命令選項(包括長格式選項)
+-----------+------------------------------------------------------------------------------------------
| groups | 顯示指定用戶的組成員關係
+-----------+------------------------------------------------------------------------------------------
| groupadd | 創建新的系統組
+-----------+------------------------------------------------------------------------------------------
| groupmod | 修改已有的系統組
+-----------+------------------------------------------------------------------------------------------
| gzip | 採用Lempel-Ziv編碼的 GNU項目壓縮工具
+-----------+------------------------------------------------------------------------------------------
| head | 顯示指定文件內容的開頭部分
+-----------+------------------------------------------------------------------------------------------
| help | 顯示bash內建命令的幫助頁面
+-----------+------------------------------------------------------------------------------------------
| killall | 根據進程名向運行中的進程發送一個系統信號
+-----------+------------------------------------------------------------------------------------------
| kwrite | 調用KWrite文本編輯器
+-----------+------------------------------------------------------------------------------------------
| less | 查看文件內容的高級方法
+-----------+------------------------------------------------------------------------------------------
| link | 用別名創建一個指向文件的鏈接
+-----------+------------------------------------------------------------------------------------------
| ln | 創建針對指定文件的符號鏈接或硬鏈接
+-----------+------------------------------------------------------------------------------------------
| ls | 列出目錄內容
+-----------+------------------------------------------------------------------------------------------
| makewhatis| 創建能夠使用手冊頁關鍵字進行搜索的whatis數據庫
+-----------+------------------------------------------------------------------------------------------
| man | 顯示指定命令或話題的手冊頁
+-----------+------------------------------------------------------------------------------------------
| mkdir | 在當前目錄下創建指定目錄
+-----------+------------------------------------------------------------------------------------------
| more | 列出指定文件的內容,在每屏數據後暫停下來
+-----------+------------------------------------------------------------------------------------------
| mount | 顯示虛擬文件系統上掛載的磁盤設備或將磁盤設備掛載到虛擬文件系統上
+-----------+------------------------------------------------------------------------------------------
| mv | 重命名文件
+-----------+------------------------------------------------------------------------------------------
| nano | 調用nano文本編輯器
+-----------+------------------------------------------------------------------------------------------
| nice | 在系統上使用不同優先級來運行命令
+-----------+------------------------------------------------------------------------------------------
| passwd | 修改某個系統用戶賬戶的密碼
+-----------+------------------------------------------------------------------------------------------
| ps | 顯示系統上運行中進程的信息
+-----------+------------------------------------------------------------------------------------------
| pwd | 顯示當前目錄
+-----------+------------------------------------------------------------------------------------------
| renice | 修改系統上運行中應用的優先級
+-----------+------------------------------------------------------------------------------------------
| rm | 刪除指定文件
+-----------+------------------------------------------------------------------------------------------
| rmdir | 刪除指定目錄
+-----------+------------------------------------------------------------------------------------------
| sed | 使用編輯器命令的文本流行編輯器
+-----------+------------------------------------------------------------------------------------------
| sleep | 在指定的一段時間內暫停bash shell操作
+-----------+------------------------------------------------------------------------------------------
| sort | 基於指定的順序組織數據文件中的數據
+-----------+------------------------------------------------------------------------------------------
| stat | 顯示指定文件的文件統計數據
+-----------+------------------------------------------------------------------------------------------
| sudo | 以root用戶賬戶身份運行應用
+-----------+------------------------------------------------------------------------------------------
| tail | 顯示指定文件內容的末尾部分
+-----------+------------------------------------------------------------------------------------------
| tar | 將數據和目錄歸檔到單個文件中
+-----------+------------------------------------------------------------------------------------------
| top | 顯示活動進程以及其他重要的系統統計數據
+-----------+------------------------------------------------------------------------------------------
| touch | 新建一個空文件,或更新一個已有文件的時間戳
+-----------+------------------------------------------------------------------------------------------
| umount | 從虛擬文件系統上刪除一個已掛載的磁盤設備
+-----------+------------------------------------------------------------------------------------------
| uptime | 顯示系統已經運行了多久
+-----------+------------------------------------------------------------------------------------------
| useradd | 新建一個系統用戶賬戶
+-----------+------------------------------------------------------------------------------------------
| userdel | 刪除已有系統用戶賬戶
+-----------+------------------------------------------------------------------------------------------
| usermod | 修改已有系統用戶賬戶
+-----------+------------------------------------------------------------------------------------------
| vi | 調用vim文本編輯器
+-----------+------------------------------------------------------------------------------------------
| vmstat | 生成一個詳盡的系統內存和CPU使用情況報告
+-----------+------------------------------------------------------------------------------------------
| whereis | 顯示指定命令的相關文件,包括二進制文件、源代碼文件以及手冊頁
+-----------+------------------------------------------------------------------------------------------
| which | 查找可執行文件的位置
+-----------+------------------------------------------------------------------------------------------
| who | 顯示當前系統中的登錄用戶
+-----------+------------------------------------------------------------------------------------------
| whoami | 顯示當前用戶的用戶名
+-----------+------------------------------------------------------------------------------------------
| xargs | 從STDIN中獲取數據項,構建並執行命令
+-----------+------------------------------------------------------------------------------------------
| zip | Windows下PKZIP程序的Unix版本
+-----------+------------------------------------------------------------------------------------------
6. 使用 Linux 環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
6.1 環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
bash shell 用一個叫作環境變量(environment variable)的特性來存儲有關shell會話和工作環境的信息(這也是它們被稱作環境變量的原因)。這項特性
允許用戶在內存中存儲數據,以便程序或 shell 中運行的腳本能夠輕鬆訪問到它們。這也是存儲持久數據的一種簡便方法。
在 bash shell中,環境變量分爲兩類:
□ 全局變量
□ 局部變量
6.1.1 全局環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
全局環境變量對於 shell 會話和所有生成的子 shell 都是可見的。局部變量則只對創建它們的 shell可見。這讓全局環境變量對那些所創建的子 shell 要
獲取父 shell 信息的程序來說非常有用。
Linux 系統在用戶開始 bash 會話時就設置了一些全局環境變量。系統環境變量基本上都是使用全大寫字母,以區別於普通用戶的環境變量。
看全局變量,可以使用 env 或 printenv 命令:
[devalone@devalone ~]$ printenv
XDG_SESSION_ID=2
HOSTNAME=devalone.sansovo.org
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.1.101 49958 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=devalone
...
[devalone@devalone ~]$ env
XDG_SESSION_ID=2
HOSTNAME=devalone.sansovo.org
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.1.101 49958 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=devalone
...
系統爲 bash shell 設置的全局環境變量數目衆多,其中有很多是在登錄過程中設置的,另外,用戶的登錄方式也會影響到所設置的環境變量。
要顯示個別環境變量的值,可以使用 printenv 命令,但是不要用 env 命令。
[devalone@devalone ~]$ printenv USER
devalone
[devalone@devalone ~]$ printenv HOME
/home/devalone
也可以使用 echo 顯示變量的值。在這種情況下引用某個環境變量的時候,必須在變量前面加上一個美元符 ($)。
[devalone@devalone ~]$ echo $HOME
/home/devalone
在 echo 命令中,在變量名前加上 $ 可不僅僅是要顯示變量當前的值。它能夠讓變量作爲命令行參數。
[devalone@devalone ~]$ ls $HOME
software study workspaces 模板 圖片 下載 桌面
devel driver programs shell_test test 公共 視頻 文檔 音樂
[devalone@devalone ~]$ ls -l $HOME/shell_test
總用量 16
drwxrwxr-x. 2 devalone devalone 4096 7月 3 10:46 new_dir
-rw-rw-r--. 1 devalone devalone 23 7月 3 14:29 sortfile
-rwxrwxr-x. 1 devalone devalone 152 7月 3 10:51 test1.sh
-rw-rw-r--. 1 devalone devalone 277 7月 3 11:26 testfile
全局環境變量可用於進程的所有子 shell:
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ ps -f
UID PID PPID C STIME TTY TIME CMD
devalone 1758 1757 0 09:17 pts/0 00:00:00 -bash
devalone 1835 1758 2 09:26 pts/0 00:00:00 bash
devalone 1865 1835 0 09:26 pts/0 00:00:00 ps -f
[devalone@devalone ~]$ echo $HOME
/home/devalone
[devalone@devalone ~]$ exit
exit
6.1.2 局部環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
局部環境變量只能在定義它們的進程中可見。儘管它們是局部的,但是和全局環境變量一樣重要。事實上,Linux 系統也默認定義了標準的局部環境變量。
不過用戶也可以定義自己的局部變量,這些變量被稱爲用戶定義局部變量。
在Linux 系統並沒有一個只顯示局部環境變量的命令。set 命令會顯示爲某個特定進程設置的所有環境變量,包括局部變量、全局變量以及用戶定義變量。
[devalone@devalone ~]$ set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d
BASH_LINENO=()
BASH_REMATCH=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="3" [2]="42" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.3.42(1)-release'
CATALINA_HOME=/home/devalone/programs/apache-tomcat-8.5.11
COLUMNS=130
COMP_WORDBREAKS=$' \t\n"\'><=;|&(:'
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
DIRSTACK=()
EUID=1000
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/home/devalone/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/home/devalone
HOSTNAME=devalone.sansovo.org
...
所有通過 printenv 命令能看到的全局環境變量都出現在了 set 命令的輸出中。但在 set 命令的輸出中還有其他一些環境變量,即局部環境變量和用戶
定義變量。
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
命令env、printenv 和 set 之間的差異很細微。set 命令會顯示出全局變量、局部變量以及用戶定義變量。它還會按照字母順序對結果進行排序。env
和 printenv 命令同 set 命令的區別在於前兩個命令不會對變量排序,也不會輸出局部變量和用戶定義變量。在這種情況下,env 和 printenv的輸出是
重複的。
6.2 設置用戶定義變量
-----------------------------------------------------------------------------------------------------------------------------------------
可以在 bash shell 中直接設置自己的變量。即在交互式 shell 或 shell 腳本程序中創建自己的變量並引用它們。
6.2.1 設置局部用戶定義變量
-----------------------------------------------------------------------------------------------------------------------------------------
一旦啓動了 bash shell(或者執行一個shell腳本),就能創建在這個shell進程內可見的局部變量了。可以通過等號給環境變量賦值,值可以是數值或字符串。
[devalone@devalone ~]$ echo $my_variable
[devalone@devalone ~]$ my_variable=hello
[devalone@devalone ~]$ echo $my_variable
hello
每次引用 my_variable 環境變量的值,只要通過 $my_variable 引用即可。如果要給變量賦一個含有空格的字符串值,必須用單引號來界定字符串的首和尾。
[devalone@devalone ~]$ my_variable=hello world
bash: world: 未找到命令...
[devalone@devalone ~]$ my_variable='hello world'
[devalone@devalone ~]$ echo $my_variable
hello world
沒有單引號的話,bash shell 會以爲下一個詞是另一個要執行的命令。注意,用戶定義的局部環境變量用的是小寫字母,而系統環境變量都是大寫字母。
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
所有的環境變量名均使用大寫字母,這是 bash shell 的標準慣例。如果是自己創建的局部變量或是 shell 腳本,請使用小寫字母。變量名區分大小寫。
在涉及用戶定義的局部變量時堅持使用小寫字母,這能夠避免重新定義系統環境變量可能帶來的災難。
記住,變量名、等號和值之間沒有空格,這一點非常重要。如果在賦值表達式中加上了空格,bash shell 就會把值當成一個單獨的命令:
[devalone@devalone ~]$ my_variable= 'hello world'
bash: hello world: 未找到命令...
設置了局部環境變量後,就能在shell進程的任何地方使用它了。但是,如果生成了另外一個 shell,它在子 shell 中就不可用。
[devalone@devalone ~]$ echo $my_variable
hello world
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ echo $my_varible
[devalone@devalone ~]$ exit
exit
[devalone@devalone ~]$ echo $my_variable
hello world
類似地,如果在子進程中設置了一個局部變量,那麼一旦退出了子進程,那個局部環境變量就不可用。
[devalone@devalone ~]$ echo $my_child_variable
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ my_child_variable='hello little world'
[devalone@devalone ~]$ echo $my_child_variable
hello little world
[devalone@devalone ~]$ exit
exit
[devalone@devalone ~]$ echo $my_child_variable
[devalone@devalone ~]$
6.2.2 設置全局環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
在設定全局環境變量的進程所創建的子進程中,該變量都是可見的。創建全局環境變量的方法是先創建一個局部環境變量,然後再把它導出到全局環境中。
這個過程通過 export 命令來完成,變量名前面不需要加$。
[devalone@devalone ~]$ my_variable='I am global now'
[devalone@devalone ~]$ export my_variable
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ exit
exit
[devalone@devalone ~]$
修改子 shell 中全局環境變量並不會影響到父 shell中該變量的值。
[devalone@devalone ~]$ my_variable='I am global now'
[devalone@devalone ~]$ export my_variable
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ my_variable="null"
[devalone@devalone ~]$ echo $my_variable
null
[devalone@devalone ~]$ exit
exit
[devalone@devalone ~]$ echo $my_variable
I am global now
子 shell 甚至無法使用 export 命令改變父 shell 中全局環境變量的值。
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ my_variable="null"
[devalone@devalone ~]$ echo $my_variable
null
[devalone@devalone ~]$ export my_variable
[devalone@devalone ~]$ echo $my_variable
null
[devalone@devalone ~]$ exit
exit
[devalone@devalone ~]$ echo $my_variable
I am global now
6.3 刪除環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
用 unset 命令刪除已經存在的環境變量。在 unset 命令中引用環境變量時,記住不要使用$。
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ unset my_variable
[devalone@devalone ~]$ echo $my_variable
[devalone@devalone ~]$
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
在涉及環境變量名時,什麼時候該使用$,什麼時候不該使用$,記住一點就行了:如果要用到變量,使用$;如果要操作變量,不使用$。這條規則的一
個例外就是使用 printenv 顯示某個變量的值。
在處理全局環境變量時,處理結果有些不同。如果是在子進程中刪除了一個全局環境變量,這隻對子進程有效。該全局環境變量在父進程中依然可用。
[devalone@devalone ~]$ my_variable="I am global now"
[devalone@devalone ~]$ export my_variable
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ bash
[devalone@devalone ~]$ echo $my_variable
I am global now
[devalone@devalone ~]$ unset my_variable
[devalone@devalone ~]$ echo $my_variable
[devalone@devalone ~]$ exit
exit
[devalone@devalone ~]$ echo $my_variable
I am global now
6.4 默認的 shell 環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
默認情況下,bash shell 會用一些特定的環境變量來定義系統環境。這些變量在 Linux 系統上都已經設置好了,只管放心使用。bash shell 源自當初的
Unix Bourne shell,因此也保留了 Unix Bourne shell裏定義的那些環境變量。
bash shell提供的與 Unix Bourne shell 兼容的環境變量:
+-----------+---------------------------------------------------------------------------------------------------------------------
| 變 量 | 描 述
+-----------+---------------------------------------------------------------------------------------------------------------------
| CDPATH | 冒號分隔的目錄列表,作爲cd命令的搜索路徑
+-----------+---------------------------------------------------------------------------------------------------------------------
| HOME | 當前用戶的主目錄
+-----------+---------------------------------------------------------------------------------------------------------------------
| IFS | shell 用來將文本字符串分割成字段的一系列字符
+-----------+---------------------------------------------------------------------------------------------------------------------
| MAIL | 當前用戶收件箱的文件名(bash shell會檢查這個文件,看看有沒有新郵件)
+-----------+---------------------------------------------------------------------------------------------------------------------
| MAILPATH | 冒號分隔的當前用戶收件箱的文件名列表(bash shell會檢查列表中的每個文件,看看有沒有新郵件)
+-----------+---------------------------------------------------------------------------------------------------------------------
| OPTARG | getopts命令處理的最後一個選項參數值
+-----------+---------------------------------------------------------------------------------------------------------------------
| OPTIND | getopts命令處理的最後一個選項參數的索引號
+-----------+---------------------------------------------------------------------------------------------------------------------
| PATH | shell查找命令的目錄列表,由冒號分隔
+-----------+---------------------------------------------------------------------------------------------------------------------
| PS1 | shell命令行界面的主提示符
+-----------+---------------------------------------------------------------------------------------------------------------------
| PS2 | hell命令行界面的次提示符
+-----------+---------------------------------------------------------------------------------------------------------------------
除了默認的 Bourne shell 的環境變量,bash shell還提供一些自有的環境變量:
+-----------------------+---------------------------------------------------------------------------------------------------------
| 變 量 | 描 述
+-----------------------+---------------------------------------------------------------------------------------------------------
| * | 含有所有命令行參數(以單個文本值的形式)
+-----------------------+---------------------------------------------------------------------------------------------------------
| @ | 含有所有命令行參數(以多個文本值的形式)
+-----------------------+---------------------------------------------------------------------------------------------------------
| # | 命令行參數數目
+-----------------------+---------------------------------------------------------------------------------------------------------
| ? | 最近使用的前臺進程的退出狀態碼
+-----------------------+---------------------------------------------------------------------------------------------------------
| - | 當前命令行選項標記
+-----------------------+---------------------------------------------------------------------------------------------------------
| $ | 當前shell的進程ID(PID)
+-----------------------+---------------------------------------------------------------------------------------------------------
| ! | 最近執行的後臺進程的PID
+-----------------------+---------------------------------------------------------------------------------------------------------
| 0 | 命令行中使用的命令名稱
+-----------------------+---------------------------------------------------------------------------------------------------------
| _ | shell的絕對路徑名
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH | 用來調用shell的完整文件名
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_ALIASES | 含有當前已設置別名的關聯數組
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_ARGC | 含有傳入子函數或shell腳本的參數總數的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_ARGV | 含有傳入子函數或shell腳本的參數的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_CMDS | 關聯數組,包含shell執行過的命令的所在位置
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_COMMAND | shell正在執行的命令或馬上就執行的命令
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_ENV | 設置了的話,每個bash腳本會在運行前先嚐試運行該變量定義的啓動文件
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_EXECUTION_STRING | 使用bash -c選項傳遞過來的命令
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_LINENO | 含有當前執行的shell函數的源代碼行號的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_REMATCH | 只讀數組,在使用正則表達式的比較運算符=~進行肯定匹配(positive match)時,包含了匹配到的模式和子模式
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_SOURCE | 含有當前正在執行的shell函數所在源文件名的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_SUBSHELL | 當前子shell環境的嵌套級別(初始值是0)
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_VERSINFO | 含有當前運行的bash shell的主版本號和次版本號的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_VERSION | 當前運行的bash shell的版本號
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASH_XTRACEFD | 若設置成了有效的文件描述符(0、1、2),則'set -x'調試選項生成的跟蹤輸出可被重定向。通常用來將跟蹤輸出到
| | 一個文件中
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASHOPTS | 當前啓用的bash shell選項的列表
+-----------------------+---------------------------------------------------------------------------------------------------------
| BASHPID | 當前bash進程的PID
+-----------------------+---------------------------------------------------------------------------------------------------------
| COLUMNS | 當前bash shell實例所用終端的寬度
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_CWORD | COMP_WORDS變量的索引值,後者含有當前光標的位置
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_LINE | 當前命令行
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_POINT | 當前光標位置相對於當前命令起始的索引
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_KEY | 用來調用shell函數補全功能的最後一個鍵
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_TYPE | 一個整數值,表示所嘗試的補全類型,用以完成shell函數補全
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_WORDBREAKS | Readline庫中用於單詞補全的詞分隔字符
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMP_WORDS | 含有當前命令行所有單詞的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| COMPREPLY | 含有由shell函數生成的可能填充代碼的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| COPROC | 佔用未命名的協進程的I/O文件描述符的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| DIRSTACK | 含有目錄棧當前內容的數組變量
+-----------------------+----------------------------------------------------------------------------------------------------------
| EMACS | 設置爲't'時,表明emacs shell緩衝區正在工作,而行編輯功能被禁止
+-----------------------+---------------------------------------------------------------------------------------------------------
| ENV | 如果設置了該環境變量,在bash shell腳本運行之前會先執行已定義的啓動文件(僅用於當bash shell以 POSIX 模式
| | 被調用時)
+-----------------------+---------------------------------------------------------------------------------------------------------
| EUID | 當前用戶的有效用戶ID(數字形式)
+-----------------------+---------------------------------------------------------------------------------------------------------
| FCEDIT | 供fc命令使用的默認編輯器
+-----------------------+---------------------------------------------------------------------------------------------------------
| FIGNORE | 在進行文件名補全時可以忽略後綴名列表,由冒號分隔
+-----------------------+---------------------------------------------------------------------------------------------------------
| FUNCNAME | 當前執行的shell函數的名稱
+-----------------------+---------------------------------------------------------------------------------------------------------
| FUNCNEST | 當設置成非零值時,表示所允許的最大函數嵌套級數(一旦超出,當前命令即被終止)
+-----------------------+---------------------------------------------------------------------------------------------------------
| GLOBIGNORE | 冒號分隔的模式列表,定義了在進行文件名擴展時可以忽略的一組文件名
+-----------------------+---------------------------------------------------------------------------------------------------------
| GROUPS | 含有當前用戶屬組列表的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| histchars | 控制歷史記錄擴展,最多可有3個字符
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTCMD | 當前命令在歷史記錄中的編號
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTCONTROL | 控制哪些命令留在歷史記錄列表中
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTFILE | 保存shell歷史記錄列表的文件名(默認是.bash_history)
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTFILESIZE | 最多在歷史文件中存多少行
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTTIMEFORMAT | 如果設置了且非空,就用作格式化字符串,以顯示bash歷史中每條命令的時間戳
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTIGNORE | 由冒號分隔的模式列表,用來決定歷史文件中哪些命令會被忽略
+-----------------------+---------------------------------------------------------------------------------------------------------
| HISTSIZE | 最多在歷史文件中存多少條命令
+-----------------------+---------------------------------------------------------------------------------------------------------
| HOSTFILE | shell在補全主機名時讀取的文件名稱
+-----------------------+---------------------------------------------------------------------------------------------------------
| HOSTNAME | 當前主機的名稱
+-----------------------+---------------------------------------------------------------------------------------------------------
| HOSTTYPE | 當前運行bash shell的機器
+-----------------------+---------------------------------------------------------------------------------------------------------
| IGNOREEOF | shell在退出前必須收到連續的EOF字符的數量(如果這個值不存在,默認是1)
+-----------------------+---------------------------------------------------------------------------------------------------------
| INPUTRC | Readline初始化文件名(默認是.inputrc)
+-----------------------+---------------------------------------------------------------------------------------------------------
| LANG | shell的語言環境類別
+-----------------------+---------------------------------------------------------------------------------------------------------
| LC_ALL | 定義了一個語言環境類別,能夠覆蓋LANG變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| LC_COLLATE | 設置對字符串排序時用的排序規則
+-----------------------+---------------------------------------------------------------------------------------------------------
| LC_CTYPE | 決定如何解釋出現在文件名擴展和模式匹配中的字符
+-----------------------+---------------------------------------------------------------------------------------------------------
| LC_MESSAGES | 在解釋前面帶有$的雙引號字符串時,該環境變量決定了所採用的語言環境設置
+-----------------------+---------------------------------------------------------------------------------------------------------
| LC_NUMERIC | 決定着格式化數字時採用的語言環境設置
+-----------------------+---------------------------------------------------------------------------------------------------------
| LINENO | 當前執行的腳本的行號
+-----------------------+---------------------------------------------------------------------------------------------------------
| LINES | 定義了終端上可見的行數
+-----------------------+---------------------------------------------------------------------------------------------------------
| MACHTYPE | 用“CPU公司系統”(CPU-company-system)格式定義的系統類型
+-----------------------+---------------------------------------------------------------------------------------------------------
| MAPFILE | 一個數組變量,當mapfile命令未指定數組變量作爲參數時,它存儲了mapfile所讀入的文本
+-----------------------+---------------------------------------------------------------------------------------------------------
| MAILCHECK | shell查看新郵件的頻率(以秒爲單位,默認值是60)
+-----------------------+---------------------------------------------------------------------------------------------------------
| OLDPWD | shell之前的工作目錄
+-----------------------+---------------------------------------------------------------------------------------------------------
| OPTERR | 設置爲1時,bash shell會顯示getopts命令產生的錯誤
+-----------------------+---------------------------------------------------------------------------------------------------------
| OSTYPE | 定義了shell所在的操作系統
+-----------------------+---------------------------------------------------------------------------------------------------------
| PIPESTATUS | 含有前臺進程的退出狀態列表的數組變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| POSIXLY_CORRECT | 設置了的話,bash會以POSIX模式啓動
+-----------------------+---------------------------------------------------------------------------------------------------------
| PPID | bash shell父進程的PID
+-----------------------+---------------------------------------------------------------------------------------------------------
| PROMPT_COMMAND | 設置了的話,在命令行主提示符顯示之前會執行這條命令
+-----------------------+---------------------------------------------------------------------------------------------------------
| PROMPT_DIRTRIM | 用來定義當啓用了\w或\W提示符字符串轉義時顯示的尾部目錄名的數量。被刪除的目錄名會用一組英文句點替換
+-----------------------+---------------------------------------------------------------------------------------------------------
| PS3 | select命令的提示符
+-----------------------+---------------------------------------------------------------------------------------------------------
| PS4 | 如果使用了bash的-x選項,在命令行之前顯示的提示信息
+-----------------------+---------------------------------------------------------------------------------------------------------
| PWD | 當前工作目錄
+-----------------------+---------------------------------------------------------------------------------------------------------
| RANDOM | 返回一個0~32767的隨機數(對其的賦值可作爲隨機數生成器的種子)
+-----------------------+---------------------------------------------------------------------------------------------------------
| READLINE_LINE | 當使用bind –x命令時,存儲Readline緩衝區的內容
+-----------------------+---------------------------------------------------------------------------------------------------------
| READLINE_POINT | 當使用bind –x命令時,表示Readline緩衝區內容插入點的當前位置
+-----------------------+---------------------------------------------------------------------------------------------------------
| REPLY | read命令的默認變量
+-----------------------+---------------------------------------------------------------------------------------------------------
| SECONDS | 自從shell啓動到現在的秒數(對其賦值將會重置計數器)
+-----------------------+---------------------------------------------------------------------------------------------------------
| SHELL | bash shell的全路徑名
+-----------------------+---------------------------------------------------------------------------------------------------------
| SHELLOPTS | 已啓用bash shell選項列表,列表項之間以冒號分隔
+-----------------------+---------------------------------------------------------------------------------------------------------
| SHLVL | shell的層級;每次啓動一個新bash shell,該值增加1
+-----------------------+---------------------------------------------------------------------------------------------------------
| TIMEFORMAT | 指定了shell的時間顯示格式
+-----------------------+---------------------------------------------------------------------------------------------------------
| TMOUT | select和read命令在沒輸入的情況下等待多久(以秒爲單位)。默認值爲0,表示無限長
+-----------------------+---------------------------------------------------------------------------------------------------------
| TMPDIR | 目錄名,保存bash shell創建的臨時文件
+-----------------------+---------------------------------------------------------------------------------------------------------
| UID | 當前用戶的真實用戶ID(數字形式)
+-----------------------+---------------------------------------------------------------------------------------------------------
不是所有的默認環境變量都會在運行 set 命令時列出。儘管這些都是默認環境變量,但並不是每一個都必須有一個值。
6.5 設置 PATH 環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
在 shell 命令行界面中輸入一個外部命令時,shell必須搜索系統來找到對應的程序。PATH 環境變量定義了用於進行命令和程序查找的目錄。
[devalone@devalone ~]$ echo $PATH
/usr/local/protoc/bin:/home/devalone/programs/apache-tomcat-8.5.11/bin:/usr/local/apache/maven/bin:/usr/local/apache/ant/bin
:/usr/java/latest/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/devalone/.local/bin:/home/devalone/bin
PATH中的目錄使用冒號分隔。
如果命令或者程序的位置沒有包括在PATH變量中,那麼如果不使用絕對路徑的話,shell 是沒法找到的。如果 shell 找不到指定的命令或程序,它會產生
一個錯誤信息:
[devalone@devalone ~]$ test2.sh
bash: test2.sh: 未找到命令...
問題是,應用程序放置可執行文件的目錄常常不在 PATH 環境變量所包含的目錄中。解決的辦法是保證 PATH 環境變量包含了所有存放應用程序的目錄。
可以把新的搜索目錄添加到現有的PATH環境變量中,無需從頭定義。PATH 中各個目錄之間是用冒號分隔的。只需引用原來的 PATH 值,然後再給這個字符串
添加新目錄就行了。參考下面的例子:
[devalone@devalone shell-script]$ pwd
/home/devalone/study/shell-script
[devalone@devalone shell-script]$ PATH=$PATH:/home/devalone/study/shell-script
[devalone@devalone shell-script]$ echo $PATH
/usr/local/protoc/bin:/home/devalone/programs/apache-tomcat-8.5.11/bin:/usr/local/apache/maven/bin:/usr/local/apache/ant/bin
:/usr/java/latest/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/devalone/.local/bin:/home/devalone/bin
:/home/devalone/study/shell-script
[devalone@devalone shell-script]$ test2.sh
User info for userid: devalone
UID: 1000
HOME: /home/devalone
程序員通常的辦法是將單點符也加入 PATH環 境變量。該單點符代表當前目錄:
[devalone@devalone shell-script]$ PATH=$PATH:.
[devalone@devalone shell-script]$ cd shell_test
[devalone@devalone shell_test]$ ll
總用量 16
drwxrwxr-x. 2 devalone devalone 4096 7月 3 10:46 new_dir
-rw-rw-r--. 1 devalone devalone 23 7月 3 14:29 sortfile
-rwxrwxr-x. 1 devalone devalone 152 7月 4 11:52 test1.sh
-rw-rw-r--. 1 devalone devalone 277 7月 3 11:26 testfile
[devalone@devalone shell_test]$ test1.sh
The time and date are: 2018年 07月 04日 星期三 11:52:45 CST
Let's see who's logged into the system:
devalone pts/0 2018-07-04 09:17 (192.168.1.101)
對 PATH 變量的修改只能持續到退出或重啓系統。這種效果並不能一直持續。
6.6 定位系統環境變量
-----------------------------------------------------------------------------------------------------------------------------------------
在登錄 Linux 系統啓動一個 bash shell時,默認情況下 bash 會在幾個文件中查找命令。這些文件叫作啓動文件或環境文件。bash 檢查的啓動文件取決於
啓動 bash shell 的方式。啓動 bash shell 有 3 種方式:
□ 登錄時作爲默認登錄shell
□ 作爲非登錄shell的交互式shell
□ 作爲運行腳本的非交互shell
6.6.1 登錄 shell
-----------------------------------------------------------------------------------------------------------------------------------------
當登錄 Linux 系統時,bash shell 會作爲登錄 shell 啓動。登錄 shell 會從 5 個不同的啓動文件裏讀取命令:
□ /etc/profile
□ $HOME/.bash_profile
□ $HOME/.bashrc
□ $HOME/.bash_login
□ $HOME/.profile
/etc/profile 文件是系統上默認的 bash shell的主啓動文件。系統上的每個用戶登錄時都會執行這個啓動文件。
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
要留意的是有些 Linux 發行版使用了可拆卸式認證模塊( Pluggable Authentication Modules ,PAM)。在這種情況下,PAM 文件會在 bash shell
啓動之前處理,這些文件中可能會包含環境變量。PAM 文件包括 /etc/environment 文件和 $HOME/.pam_environment文件。
另外 4 個啓動文件是針對用戶的,可根據個人需求定製。
■ /etc/profile 文件
-------------------------------------------------------------------------------------------------------------------------------------
/etc/profile 文件是 bash shell 默認的的主啓動文件。只要用戶登錄了 Linux 系統,bash 就會執行 /etc/profile 啓動文件中的命令。不同的Linux
發行版在這個文件裏放了不同的命令。
[devalone@devalone shell_test]$ cat /etc/profile
# /etc/profile
# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}
if [ -x /usr/bin/id ]; then
if [ -z "$EUID" ]; then
# ksh workaround
EUID=`id -u`
UID=`id -ru`
fi
USER="`id -un`"
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
fi
# Path manipulation
if [ "$EUID" = "0" ]; then
pathmunge /usr/sbin
pathmunge /usr/local/sbin
else
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after
fi
HOSTNAME=`/usr/bin/hostname 2>/dev/null`
HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
export HISTCONTROL=ignoreboth
else
export HISTCONTROL=ignoredups
fi
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then
umask 002
else
umask 022
fi
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done
unset i
unset -f pathmunge
注意,用戶的一些自定義信息儘量不要在這個文件上修改,可以在 /etc/profile.d/ 目錄下創建自定義的配置文件,設置相關信息,系統在讀取執行
/etc/profile 腳本文件時,會迭代讀取執行 /etc/profile.d/ 目錄下的所有文件。
■ $HOME 目錄下的啓動文件
-------------------------------------------------------------------------------------------------------------------------------------
剩下的啓動文件都起着同一個作用:提供一個用戶專屬的啓動文件來定義該用戶所用到的環境變量。大多數 Linux 發行版只用這四個啓動文件中的一到
兩個:
$HOME/.bash_profile
$HOME/.bashrc
$HOME/.bash_login
$HOME/.profile
注意,這四個文件都以點號開頭,這說明它們是隱藏文件。它們位於用戶的 HOME 目錄下,所以每個用戶都可以編輯這些文件並添加自己的環境變量,這
些環境變量會在每次啓動 bash shell 會話時生效。
shell 會按照按照下列順序,運行第一個被找到的文件,餘下的則被忽略:
$HOME/.bash_profile
$HOME/.bash_login
$HOME/.profile
注意,這個列表中並沒有 $HOME/.bashrc 文件。這是因爲該文件通常通過其他文件運行的。
[devalone@devalone shell_test]$ cat ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
.bash_profile 啓動文件會先去檢查 HOME 目錄中是不是還有一個叫 .bashrc 的啓動文件。如果有的話,會先執行啓動文件裏面的命令。
6.6.2 交互式 shell 進程
-----------------------------------------------------------------------------------------------------------------------------------------
如果 bash shell 不是登錄系統時啓動的(比如是在命令行提示符下敲入bash時啓動),這樣啓動的 shell 叫作交互式 shell。交互式 shell 不會像登錄
shell 一樣運行,但它依然提供了命令行提示符來輸入命令。
如果 bash 是作爲交互式 shell 啓動的,它就不會訪問 /etc/profile 文件,只會檢查用戶 HOME 目錄中的 .bashrc文件。
[devalone@devalone ~]$ cat .bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
.bashrc 文件有兩個作用:一是查看並執行 /etc 目錄下通用的 bashrc 文件,二是爲用戶提供一個定製自己的命令別名和私有腳本函數的地方。
6.6.3 非交互式 shell 進程
-----------------------------------------------------------------------------------------------------------------------------------------
系統執行 shell 腳本時用的就是這種 shell,不同的是它沒有命令行提示符。但是當用戶在系統上運行腳本時,也許希望能夠運行一些特定啓動的命令。
爲了處理這種情況,bash shell 提供了 BASH_ENV 環境變量。當 shell 啓動一個非交互式 shell 進程時,它會檢查這個環境變量來查看要執行的啓動文件。
如果有指定的文件,shell 會執行該文件裏的命令,這通常包括 shell 腳本變量設置。
那如果 BASH_ENV 變量沒有設置,shell 腳本到哪裏去獲得它們的環境變量呢?別忘了有些 shell 腳本是通過啓動一個子 shell 來執行的,子 shell 可以
繼承父 shell 導出過的變量。
例如,如果父 shell 是登錄 shell,在 /etc/profile、/etc/profile.d/*.sh 和 $HOME/.bashrc 文件中設置並導出了變量,用於執行腳本的子 shell 就
能夠繼承這些變量。
由父 shell 設置但並未導出的變量都是局部變量。子 shell 無法繼承局部變量。
對於那些不啓動子 shell 的腳本,變量已經存在於當前 shell 中了。所以就算沒有設置 BASH_ENV,也可以使用當前 shell 的局部變量和全局變量。
6.6.4 環境變量持久化
-----------------------------------------------------------------------------------------------------------------------------------------
對全局環境變量來說(Linux 系統中所有用戶都需要使用的變量),可能更傾向於將新的或修改過的變量設置放在 /etc/profile 文件中,但這可不是什麼
好主意。如果升級了所用的發行版,這個文件也會跟着更新,那所有定製過的變量設置可就都沒有了。
最好是在 /etc/profile.d 目錄中創建一個以 .sh 結尾的文件。把所有新的或修改過的全局環境變量設置放在這個文件中。
在大多數發行版中,存儲個人用戶永久性 bash shell 變量的地方是 $HOME/.bashrc文件。這一點適用於所有類型的 shell進程。但如果設置了 BASH_ENV變量,
那麼記住,除非它指向的是 $HOME/.bashrc,否則應該將非交互式 shell 的用戶變量放在別的地方。
6.7 數組變量
-----------------------------------------------------------------------------------------------------------------------------------------
環境變量有一個很好的特性就是,它們可作爲數組使用。數組是能夠存儲多個值的變量。這些值可以單獨引用,也可以作爲整個數組來引用。
要給某個環境變量設置多個值,可以把值放在括號裏,值與值之間用空格分隔。
[devalone@devalone ~]$ mytest=(one two three four five)
如果想把數組像普通的環境變量那樣顯示,會失望的:
[devalone@devalone ~]$ echo $mytest
one
只有數組的第一個值顯示出來了。要引用一個單獨的數組元素,就必須用代表它在數組中位置的數值索引值。索引值要用方括號括起來。
[devalone@devalone ~]$ echo ${mytest[2]}
three
環境變量數組的索引值都是從零開始。
要顯示整個數組變量,可用星號作爲通配符放在索引值的位置。
[devalone@devalone ~]$ echo ${mytest[*]}
one two three four five
也可以改變某個索引值位置的值:
[devalone@devalone ~]$ mytest[2]=seven
[devalone@devalone ~]$ echo ${mytest[*]}
one two seven four five
甚至能用 unset 命令刪除數組中的某個值:,但是要小心,可能會有點複雜。
[devalone@devalone ~]$ unset mytest[2]
[devalone@devalone ~]$ echo ${mytest[*]}
one two four five
[devalone@devalone ~]$ echo ${mytest[2]}
[devalone@devalone ~]$ echo ${mytest[3]}
four
用 unset 命令刪除在索引值爲 2 的位置上的值。顯示整個數組時,看起來像是索引裏面已經沒這個索引了。但當專門顯示索引值爲 2 的位置上的值時,
就能看到這個位置是空的。
可以在 unset 命令後跟上數組名來刪除整個數組。
[devalone@devalone ~]$ unset mytest
[devalone@devalone ~]$ echo ${mytest[*]}
[devalone@devalone ~]$
有時數組變量會讓事情很麻煩,所以在 shell 腳本編程時並不常用。對其他 shell 而言,數組變量的可移植性並不好。
參考:
《Linux 命令行與 shell 腳本編程大全》 第 3 版 —— 2016.8(美)Richard Blum Cristine Bresnahan