一、 shell簡介
1. shell的類型
系統啓用什麼樣的shell取決於用戶配置,在/etc/passwd的最後一個字段列出了用戶的默認shell,一般爲/bin/bash,其他還有zsh,tcsh,dash,csh等。
bash shell程序位於/bin目錄下,使用長列表可以看出它是一個可執行程序:
另外一個默認的shell是/bin/sh,作爲默認的系統shell,用於需要在啓動時使用的系統shell腳本。centos中使用軟鏈接將默認的系統shell設置成bash shell。這樣說來,sh其實就是bash。
2. shell的父子關係
bash shell及之前提到的shell 都是父shell,要創建一個子shell程序很簡單,輸入bash就會創建一個新的shell程序,被稱爲子shell。要區分是父shell還是子shell,需要使用ps 查看進程。
在root用戶下,先看沒有子shell的父shell進程,如下圖所示:
接下來輸入bash,創建一個子shell,該子shell的PPID父進程是1748,對應-bash進程的(PID) 1748
當然子shell還可以繼續創建子shell,但注意生成子shell的成本不低,速度還慢,創建嵌套的子shell去處理性能更爲糟糕。
可以用ps -forest命令查看樹狀關係圖
3. 命令列表與進程列表
通過;可以在一行中執行一系列命令,稱爲命令列表,例如
pwd ; ls ; cd /etc ; pwd ; ls
上面的命令可以依次執行,但這並不是進程列表。命令列表要想變爲進程列表,將這些命令包含在()中即可。
(pwd ; ls ; cd /etc ; pwd ; ls)
對於進程列表,Linux會生成一個子shell執行對應命令。Linux有一個環境變量 $BASH_SUBSHELL,可以查看該值判斷是否有子shell(爲0則沒有)。
pwd ; ls ; cd /etc ; pwd ; ls ; echo $BASH_SUBSHELL # echo $BASH_SUBSHELL返回0
(pwd ; ls ; cd /etc ; pwd ; ls ; echo $BASH_SUBSHELL) # echo $BASH_SUBSHELL返回1
4. 外部命令與內建命令
外部命令即存在於bash shell之外的程序,通常位於各類bin目錄下,例如ps、sqlplus等。執行外部命令會自動forking出一個子進程,由子進程實際執行該外部命令。前面說過forking子進程需要額外代價,因此外部命令效率相對較低。
內建命令則是存在於bash shell中的程序,它們和shell編譯成了一體,例如cd、exit等。
可以使用type查看命令是外部命令還是內建命令
type ps
type cd
二、 shell變量
編程語言總繞不過變量,shell也是一樣。bash中每個變量都是字符串,都以字符串形式存儲。
1. 變量分類及使用
- 根據是系統自帶還是用戶自定義,分爲:環境變量、用戶定義變量
- 根據作用範圍又分爲:全局變量、局部變量
① 環境變量
用於存儲shell會話和工作環境信息,通常是事先定義好的。
- 全局環境變量:對所有shell都可見
#查看所有與此終端相關的環境變量
env
#或
printenv
#查看進程環境變量
cat /proc/$PID/env
#查看單個環境變量值
printenv $ORACLE_HOME
echo $ORACLE_HOME
- 局部環境變量:只對創建它們的shell可見。Linux中沒有隻顯示局部環境變量的命令
#set 命令可顯示爲特定進程設置的所有變量,包括局部、全局環境變量、用戶定義變量,還會按字母排序,輸出通常很長
set
② 用戶定義變量
- 局部用戶定義變量:在當前shell進程中創建的僅當前進程可見的變量(子進程不可見)
使用等號=定義
my_var=123 #等號兩邊不要有空格
echo $my_var
my_var2="Hello World"
echo $my_var2
#刪除變量
unset my_var2
- 全局用戶定義變量:在當前shell進程創建的當前進程及其子進程可見的變量(注意對別的進程和其父進程還是不可見的)
使用export可將變量導出至全局環境(對其子進程可見)
2. 默認的shell環境變量
以下僅爲部分,完整版非常長,大部分編程時也用不上,不列出了
variable_name | variable_value | instructions |
BASH | /bin/bash | bash二進制執行文件 |
BASH_VERSINFO[0] | 4 | 主版本號 |
BASH_VERSINFO[1] | 2 | 次版本號 |
BASH_VERSINFO[2] | 46 | 更新次數 |
BASH_VERSINFO[3] | 2 | 構建次數 |
BASH_VERSINFO[4] | release | 分發狀態 |
BASH_VERSINFO[5] | x86_64-redhat-linux-gnu | 架構 |
BASH_VERSION | 4.2.46(2)-release | bash版本號 |
DIRSTACK | $PWD | 當前目錄 |
FUNCNAME | 正在執行的函數的名字 | 可以放在函數裏定位函數執行過程 |
GROUPS | 0 | 當前登錄的用戶所屬組的組id號,root默認爲0 |
HOME | /root | 當前登錄的用戶家目錄 |
HOMENAME | 主機名 | 主機名 |
HOSTTYPE | x86_64 | 設備硬件類型 |
IFS | 內部域分隔,默認爲空白,可以自定義設置 | Bash 在解釋字符串時如何識別域,或者單詞邊界 |
LINENO | 記錄其所在的行號 | 記錄其所在shell腳本中的行號 |
MACHTYPE | 系統硬件架構 | 系統設備 |
3. 定位系統環境變量
當登入Linux系統啓動bash shell時,bash默認會在幾個文件中查找可執行命令,這些文件稱爲啓動文件或環境文件。
根據不同的bash啓動方式,檢查的啓動文件有所不同:
- 登錄時作爲默認登錄shell
- 非登錄時的交互式shell
- 非交互式shell
① 登錄時作爲默認登錄shell
當登入Linux系統時,bash shell會作爲登錄shell啓動,此時會從5個啓動文件中查找可執行命令。
- /etc/profile
- $HOME/.bash_profile
- $HOME/.bashrc
- $HOME/.bash_login
- $HOME/.profile
其中/etc/profile是共用的,是默認的主啓動文件,每個用戶登錄時都會執行。
其餘4個不一定存在,一般建在各用戶家目錄下,針對每個用戶進行定製。shell會按照以下順序運行第一個被找到的文件,其他則被忽略。
- $HOME/.bash_profile
- $HOME/.bash_login
- $HOME/.profile
可以看到順序中並沒有$HOME/.bashrc文件,它的檢查和調用包含在$HOME/.bash_profile中
可以看到$HOME/.bashrc做了兩件事:
- 定製命令別名
- 查找/etc/bashrc文件(不建議修改),若存在則調用
② 非登錄時的交互式shell
如果bash shell不是在登錄時啓動也不是在腳本中啓動,而是類似在命令行中輸入bash啓動的,它就不會訪問/etc/profile文件,只檢查$HOME/.bashrc文件
③ 非交互式shell
運行腳本時的情況,bash會檢查BASH_ENV環境變量,若設置則使用。若未設置,對於會啓動子shell的腳本,會繼承父shell的全局變量;對於不啓動子shell的腳本,則執行進程爲當前進程,可使用當前進程所有變量。
4. 數組變量
要給某個變量設置多個值,可以將值放在括號中並用空格分隔,不太常用但可以瞭解。
mydb=(oracle mysql mssql pg redis)
#僅顯示第一個值
echo $mydb
#顯示指定下標值(從0開始)
echo ${mydb[3]}
#顯示所有值
echo ${mydb[*]}
參考:《Linux命令行與shell腳本編程大全》