----- 最近更新【2021-12-30】-----
本文目錄結構預覽:
- 一、簡介
- 二、shell 變數
1、檢視變數
2、變數型別
3、變數操作
4、系統常見的全域性變數 - 三、shell 選項
1、檢視 shell 選項
2、設定 shell 選項 - 四、元字元
1、元字元列表
2、引用與轉義 - 五、shell 內建命令
1、檢視說明
2、常用內建命令 - 六、搜尋路徑
1、檢視搜尋路徑
2、修改搜尋路徑 - 七、歷史列表
1、檢視歷史列表
2、調取歷史命令
3、調取並修改歷史命令
4、搜尋歷史命令
5、設定歷史列表大小 - 八、別名 alias
1、語法
2、建立別名
3、檢視別名
4、移除別名
5、不使用別名 - 九、初始化檔案
1、檔名稱
2、登入 shell 與 非登入 shell
3、初始化檔案內容 - 十、參考
一、簡介
簡單地來說,shell 就是一個 Unix 程式,充當使用者介面和指令碼直譯器,允許使用者輸入命令以及間接地訪問核心的服務。
從功能方面來說:
第一,shell 是一個讀取並解釋所輸入命令的程式。使用者每輸入一條 Unix 命令,shell 就讀取該命令,並指出應該怎麼做,所以 shell 是一個命令處理器。
第二,shell 還支援一些型別的程式語言。使用該語言可以編寫由 shell 解釋的程式,這些程式稱為 shell 指令碼。
目前比較流行的shell有以下幾種 :Bash、Korn shell、C-Shell、Tcsh。
Bash是目前最流行的 shell,本文也是以 Bash 為環境。
如果不知道你目前使用的是哪種 shell,可以使用命令echo $SHELL
來檢視。
本文內容可能會比較多,為了方面提前知道有哪些內容,這裡先作一個簡要的列表:
- shell 變數
--檢視變數、變數型別、變數操作、系統常見的全域性變數 - shell 選項
--檢視 shell 選項、設定 shell 選項 - 元字元
--元字元列表、引用與轉義 - shell 內建命令
--檢視說明、常用內建命令 - 搜尋路徑
--檢視搜尋路徑、修改搜尋路徑 - 歷史列表
--檢視歷史列表、調取歷史命令、調取並修改歷史命令、搜尋歷史命令、設定歷史列表大小 - 別名 alias
--語法、建立別名、檢視別名、移除別名 - 初始化檔案
--檔名稱、登入 shell 與 非登入 shell、初始化檔案內容
二、shell 變數
1、檢視變數
上面說的$SHELL
是 shell 的一個全域性變數,shell 中還有很多其它的變數。可以使用命令env
或者printenv
去檢視全域性變數。
使用不帶選項或者引數的 set
命令也可以顯示所有的 shell 變數以及它們的值。
2、變數型別
根據儲存型別,shell變數幾乎總是儲存一種型別的資料,即字串。
根據變數的作用域(Scope),shell 變數可以劃分為以下三種型別:
- 有的變數可以在當前shell程式及其子程式中使用,這叫做全域性變數
- 有的變數僅可以在當前shell程式中使用,這叫做環境變數
- 有的變數只能在函式內部使用,這叫做區域性變數(作用域僅為某程式碼片斷(函式上下文))
如果使用export
命令將環境變數匯出,那麼它就在所有的子程式中也可以使用了,這時稱為“全域性變數”。
很多書本或網站對環境變數與全域性變數的定義都比較模糊,我這裡採用一種比較好理解的方式來定義。
3、變數操作
變數通常有4種不同型別的操作,即建立變數、檢視變數、修改變數、刪除變數。
變數的建立非常簡單,使用如下語法就行:
變數名稱=變數值 # 注意!等號前後不能有空格。
刪除變數:
unset 變數名 ...
例:
[14:59 linux1@noseeu ~]$ MYNAME=Nosee #建立變數(當前shell可用)
[14:59 linux1@noseeu ~]$ echo $MYNAME #檢視變數
Nosee
[14:59 linux1@noseeu ~]$ export $MYNAME #匯出變數(當前shell及子程式可用)
[15:00 linux1@noseeu ~]$ unset MYNAME #刪除變數
[15:00 linux1@noseeu ~]$ echo $MYNAME
[15:00 linux1@noseeu ~]$
注意:
通過 export 匯出的變數只對當前 Shell 程式以及所有的子程式有效,如果最頂層的父程式被關閉了,那麼這個全域性變數也就隨之消失了,其它的程式也就無法使用了,這個變數只是臨時的。
只有將變數寫入 Shell 配置檔案中才能達到永久的目的,Shell 程式每次啟動時都會執行配置檔案中的程式碼做一些初始化工作,如果將變數放在配置檔案中,那麼每次啟動程式都會定義這個變數。
4、系統常見的全域性變數
HISTFILE # 歷史列表:用來儲存歷史命令的檔名稱
HISTSIZE # 歷史列表:用來儲存歷史命令的最大數目
HOME # home目錄
HOSTNAME # 計算機名稱
LOGNAME # 當前使用者標誌(使用者名稱)
PATH # 程式搜尋目錄
PS1 # shell提示
PWD # 當前工作目錄
SHELL # shell型別
TERM # 終端型別
USER # 當前使用者標誌(使用者名稱)
三、shell 選項
在Bash shell中,當我們需要控制 shell 行為的各個方面時,則可以使用shell 選項。
shell 選項就像 on/off 開關一樣。當開啟一個選項時,就說設定了這個選項;當關閉這個選項時,就說復位了這個選項。
shell 選項或者是 off 或者是 on ,它們不需要建立。
1、檢視 shell 選項
可以使用命令set -o
或者set +o
來檢視所有 shell 選項,兩種檢視方式只是在顯示格式上不一樣。
set -o
命令以一種易於閱讀的方式顯示(人類可讀)
set +o
命令顯示的輸出適合用作 shell 指令碼的資料(機器可讀)
選項介紹:
選項 | 短名稱 | 含義 |
---|---|---|
allexport | -a | 匯出隨後定義的所有變數和函式 |
braceexpand | -B | 啟用括號擴充套件(生成字元模式) |
emacs | 命令列編輯器:Emacs模式,關閉vi模式 | |
hashall | -h | 查詢到命令時(記住)的命令雜湊位置 |
hisexpand | -H | 歷史列表:啟用!風格替換 |
history | 歷史列表:啟用 | |
ignoreeof | 忽略eof訊號^D;使用exit或logout退出shell | |
minitor | -m | 作業控制:啟用 |
noclobber | -C | 不允許重定向的輸出替換某個檔案 |
notify | -b | 作業控制:當後臺作業結束時立即通知 |
vi | vi模式:立即處理每個鍵入的字元 |
使用命令 shopt
可以檢視更多的 shell 選項。
2、設定 shell 選項
語法:
set -o option # 開啟shell選項(開啟)
set +o option #復位shell選項(關閉)
注意,這裡的-o
表示開啟一個選項,+o
表示關閉一個選項。
1)如,我要開啟某個選項(選項noclobber
表示不允許重定向的輸出替換某個檔案)
則可以:
set -o noclobber # 開啟該選項
或者:
set -C
關閉該選項則這樣:set +o noclobber
或set +C
2)忽略eof訊號^D
[21:34 linux1@noseeu ~]$ set -o ignoreeof
# 此時我再按 <Crlt>-D 組合鍵
[21:34 linux1@noseeu ~]$ Use "logout" to leave the shell.
設計 shell 的程式設計師們知道人們會如何使用 shell,因此在大多數情況下,預設的 shell 選項就可以滿足要求。這意味著我們極少需要雲修改 shell 選項。
四、元字元
在shell中,有許多字元擁有它特殊的含義,我們稱這樣的字元為元字元。如;
(分號)、\
(反斜槓)、.
(點號),抽象一點的如按鍵<Space>
、<Tab>
、<Enter>
也是使用了元字元。
1、元字元列表
字元 | 名稱 | 作用 |
---|---|---|
| | 管道 | 命令列:建立一個管道線 |
< | 小於 | 命令列:重定向輸入 |
> | 大於 | 命令列:重定向輸出 |
() | 圓括號 | 命令列:在子shell中執行命令 |
# | hash、pound | 命令列:註釋 |
; | 分號 | 命令列:用於分隔多條命令 |
` | 反引號 | 命令列:命令替換 |
~ | 波浪號 | 檔名擴充套件:插入home目錄的名稱 |
? | 問號 | 檔名擴充套件:匹配任意一個字元 |
[] | 方括號 | 檔名擴充套件:與一組字元中的字元匹配 |
* | 星號 | 檔名擴充套件:匹配0個或多個字元 |
! | 歎號、bang | 歷史列表:事件標記 |
& | 和號 | 作業控制:在後臺執行命令 |
\ | 反斜槓 | 引用:下一個字元轉義 |
' | 單引號 | 引用:取消所有的替換 |
" | 雙引號 | 引用:取消大部分替換 |
{} | 花括號 | 變數:確定變數名稱的界限 |
$ | 美元符號 | 變數:用變數的值替換 |
空格符 | 空白符:在命令列中分隔單詞 | |
製表符 | 空白符:在命令列中分隔單詞 | |
新行字元 | 空白符:標記一行結束 |
以上元字元列表展示的就是元字元在shell中的常用作用。
2、引用與轉義
有時候,我們希望按字面上的含義使用元字元(而不是使用其特殊含義),這時我們必須告訴shell按字面意思解釋字元。這樣做時,可以稱其為引用字元。
字元的引用有3種方法:使用反斜槓、一對單引號或者一對雙引號。
當使用反斜槓引用單個字元時,我們稱反斜槓為“轉義字元”。
如:
echo It is warm\; come on.
上面例子中,;
(分號)在shell中有特殊的含義,如果我們想原樣輸出則必須轉義。這時可以說“使用反斜槓轉義了分號”,或者可以說“使用反斜槓引用了分號”。
當元字元少時,上面的方法沒有什麼問題。但是當元字元多的時候,我們就需要用到單引號或者雙引號了。
1)強引用(單引號)
單引號裡面的所有元字元都會被轉義,也就是所有元字元都會原樣輸出。
如,下面的$
會被轉義,$NAME
會原樣輸出:
linux1@noseeu:~$ echo 'My name is $NAME'
My name is $NAME
2)弱引用(雙引號)
雙引號引用時,會保留$
(美元符號)、`
(反引號)、\
(反斜槓)的特殊含義。
如:
linux1@noseeu:~$ echo "My name is $NAME"
My name is Chan
[22:04 linux1@noseeu ~]$ echo "now is `date`."
now is Sun 26 Dec 2021 10:04:24 PM UTC.
上面的$
不會被轉義,$NAME
會被替換為NAME
的實際值;`
也不會被轉義,date
會被當作嵌入命令優先執行。
注:反斜槓是所有引用中最強的,所以它甚至可以引用新行字元(<Enter>
)。
如,
linux1@noseeu:~$ echo hi \
> nosee.
hi nosee.
linux1@noseeu:~$ date;\
> cal
Sun 26 Dec 2021 05:28:01 PM UTC
December 2021
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
在這裡新行字元(<Enter>
)失去了它的特殊含義,所以這時它並不是一行結束的訊號了,意味著後面輸入的內容都是接著上一行的。
五、shell 內建命令
當在shell中輸入命令時,shell會將命令進行解析,然後決定如何處理命令,其中有兩種可能。一些命令在shell的內部,這意味著shell可以直接解釋它們,這些命令是內部命令,稱為內建命令。其他所有命令都是外部命令,即必須獨自執行的獨立程式。
當輸入內建命令時,shell在自己的程式內執行該命令(不建立新的程式)。當輸入外部命令時,shell將搜尋合適的程式然後以一個單獨的程式執行該命令(建立一個子程式)。
檢視某一條命令是不是內建命令的快捷方法是使用type
。如:
linux1@noseeu:~$ type time set date type
time is a shell keyword
set is a shell builtin
date is hashed (/usr/bin/date)
type is a shell builtin
可以看出,time、set、type都是shell的內建命令,而date是外部命令。
1、檢視說明
幾乎所有的Unix程式在發行的時候都提供有說明明書頁,即可以用man
或者info
去檢視它們的說明。但內建命令不是一個單獨的程式,它們是shell的一部分,每種shell都會提供大量的命令,所以每個內建命令都開發一個單獨的說明書頁是不現實的。
其實,所有的內建命令都記錄在shell的說明書頁中,即你可以使用man bash
去檢視。但是shell的說明書頁都非常長,可能需要使用搜尋才能找到所需的內容(可以使用apropos
命令或者man -k
命令進行搜尋)。
還有一個方法,就是使用help
命令也可以檢視內建命令的說明,如:help unset
linux1@noseeu:~$ help unset
unset: unset [-f] [-v] [-n] [name ...]
Unset values and attributes of shell variables and functions.
...
...
Exit Status:
Returns success unless an invalid option is given or a NAME is read-only.
使用不帶引數的help
命令,可以顯示一個所有內建命令的摘要列表。如下圖:
使用help -s
命令可以檢視某個內建命令的語法:
linux1@noseeu:~$ help -s set
set: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
2、常用內建命令
alias # 為指定命令定義一個別名
echo # 將指定字串輸出到STDOUT
exit # 強制 shell 以指定的退出狀態碼退出
export # 將變數匯出到全域性變數
fc # 從歷史記錄中選擇命令列表
help # 顯示幫助說明
history # 顯示命令歷史記錄
kill # 向指定的程式 ID(PID) 傳送一個系統訊號
pwd # 顯示當前工作目錄的路徑名
set # 設定並顯示環境變數的值和 shell 屬性
shopt # 開啟/關閉控制 shell 可選行為的變數值
type # 顯示指定的單詞如果作為命令將會如何被解釋
unset # 刪除指定的環境變數或 shell 屬性
六、搜尋路徑
大部分命令都不是 shell 內建的,那麼 shell 必須查詢出合適的程式來執行。那麼 shell 在哪裡查詢外部命令?
shell 通過查詢變數 PATH
來獲得一系列目錄名稱,然後在這些目錄下尋找對應的程式,這些目錄名稱就是我們所說的搜尋路徑。
1、檢視搜尋路徑
搜尋路徑是包含所有外部命令的程式的目錄列表,使用命令echo $PATH
可以檢視 搜尋路徑。
[21:31 linux1@noseeu ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
搜尋順序:
當 shell 在查詢外部程式時,它在搜尋路徑中會按指定順序逐個檢查目錄,進到找到期望的外部命令時,它就停止搜尋並執行程式。
2、修改搜尋路徑
修改搜尋路徑的基本思想就是將修改PATH
變數的命令放到登入時自動執行的初始化檔案中。
PATH
的值就是一個包含若干目錄名稱的字串,各個目錄名稱用:
(冒號)隔開。
如我有一些自定義的程式放在 ~/bin 目錄,那麼我可以這樣設定:
export PATH="$PATH:$HOME/bin"
一般修改 PATH
的值我們都是在原有的路徑上再加上我們想要新增的路徑。
七、歷史列表
在輸入命令時,shell 會將命令儲存到所謂的歷史列表中。然後我們可以採用不同方式訪問歷史列表,調取前面的命令,然後再對命令進行修改,並重新輸入命令。
1、檢視歷史列表
最簡單的檢視歷史列表的辦法就是使用<Up>
和<>Down
鍵,但是這個方法每次只能檢視一條命令。
還有一個更強大的命令,可以檢視全部或者部分歷史命令,就是使用history
或者fc
命令。
在歷史列表中,每條命令稱為一個事件,而每個事件都有一個內部編號,稱為事件編號。歷史列表的主要功能就是它可以基於事件編號調取命令。
檢視歷史列表:
[23:12 linux1@noseeu ~]$ fc -l
...
931 echo "'now is `date`."
932 help fc
933 fc-l
[23:12 linux1@noseeu ~]$ history
1 sudo -i
2 exit
...
934 fc -l
935 history
每條命令前面的數字就是事件編號。
2、調取歷史命令
如我們想再次執行932號命令,可以使用fc -s 932
或者!932
。
[23:14 linux1@noseeu ~]$ fc -s 932
help fc
fc: fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
...
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
[23:22 linux1@noseeu ~]$ !932
help fc
fc: fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
...
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
如果只是希望輸入最近上一條命令,則可以不帶事件編號:fc -s
或者!!
3、調取並修改歷史命令
shell 允許在重新執行歷史命令之前對命令進行小的修改,語法如下:
fc -s pattern=replacement number
!number:s/pattern/replacement
例:
937 vim sh_test1
[23:34 linux1@noseeu ~]$ fc -s sh_=Sh 937
vim Shtest1
[23:35 linux1@noseeu ~]$ !937:s/sh_/Sh
vim Shtest1
如果只是想修改上一條輸錯的命令,還可以這樣:
[23:39 linux1@noseeu ~]$ datw
Command 'datw' not found.
[23:39 linux1@noseeu ~]$ ^w^e
date
Sun 26 Dec 2021 11:40:12 PM UTC
[23:40 linux1@noseeu ~]$
記住,這個方法僅適用於對上一條歷史命令修改。
4、搜尋歷史命令
bash 還提供了一個非常方便的歷史命令搜尋方式,即使用<Ctrl>-R
(^R)。
如我需要調取一條設定PS1變數的命令,查歷史列表又覺得麻煩。這時我就可以按下<Ctrl>-R
鍵,然後輸入關鍵詞PS:
linux1@noseeu:~$
(reverse-i-search)`PS': PS1="\[\033[0;32m\][\A \u\[\033[0;33m\]@\H \w]$ \[\033[0m\]"
如果顯示出的命令是你想要的,直接按回車就可以執行了:
linux1@noseeu:~$ PS1="\[\033[0;32m\][\A \u\[\033[0;33m\]@\H \w]$ \[\033[0m\]"
[23:54 linux1@noseeu ~]$
如果看到的不是你想要的命令,可以繼續按<Ctrl>-R
搜尋下一個。
5、設定歷史列表大小
Bash shell 將歷史列表儲存在一個檔案中,所以下次登入時還是可以繼續使用。為了避免歷史列表太多,shell 允許通過設定一個變數來設定歷史列表的大小。
檢視 shell 預設設定:
linux1@noseeu:~$ set | grep HIST
HISTCONTROL=ignoreboth
HISTFILE=/home/linux1/.bash_history
HISTFILESIZE=2000
HISTSIZE=1000
如我們要修改history
命令所展示的歷史列表條數:
linux1@noseeu:~$ export HISTSIZE=10
八、別名 alias
別名就是賦予一條命令或者一列命令的名稱。可以將別名作為縮寫,或者使用別名建立已有命令的自定義變體。
1、語法
Define or display aliases.
alias: alias [-p] [name[=value] ... ]
2、建立別名
我們經常會使用ls -al
來檢視檔案列表,為了方便可以如下定義別名:
alias ll='ls -al'
當一條命令中包含有空格或元字元時,記得要使用引號包圍。
linux1@noseeu:~$ alias mytime='date; cal'
linux1@noseeu:~$ mytime
Mon 27 Dec 2021 01:01:56 AM UTC
December 2021
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
3、檢視別名
當需要檢視某個別名的含義時,可以這樣:
linux1@noseeu:~$ alias mytime
alias mytime='date; cal'
或者使用type
命令:
linux1@noseeu:~$ type mytime
mytime is aliased to `date; cal'
檢視所有別名:
linux1@noseeu:~$ alias
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -al'
alias ls='ls --color=auto'
alias mytime='date; cal'
4、移除別名
語法:Remove each NAME from the list of defined aliases.
unalias [-a] name [name ...]
例:
linux1@noseeu:~$ unalias mytime
linux1@noseeu:~$ mytime
mytime: command not found
5、不使用別名
如ls
命令,很多 linux 會預設就在配置檔案中設定了ls --color=auto
,這時你就會在不知情的情況下使用了別名。如果你不想使用使用別名,可以在命令前面鍵入一個\
,告訴 shell 不使用任何別名,如\ls
。
九、初始化檔案
以上所說的所有設定都是隻有當前shell生效,登出然後再登入之後那些設定都不存在了。如果你想在你下次登入時還可以繼續使用你的設定,則需要把你的設定新增到初始化檔案中。
Bash shell 的初始化檔案包括兩個,即登入檔案和環境檔案。
初始化檔案存放著所有希望在每次登入時自動執行的命令,而環境檔案存放著所有希望在新 shell 啟動時自動執行的程式。
為了提供更多的功能,Bash shell 還提供了登出檔案,用於存放登出登入時自動執行的命令。
1、檔名稱
初始化檔案的名稱在不同的系統中可能會稍有不同,但基本都是以下這種:
執行環境 | 檔名稱 |
---|---|
登入檔案 | .bash_profile、.profile、.bash_login |
環境檔案 | .bashrc |
登出檔案 | .bash_logout |
檔案存放的目錄都為使用者目錄,即:/home/使用者名稱
注:
系統啟動的時候會先執行.profile
然後執行.bashrc
,所以如果這兩個檔案存在相同的配置的話,前面的會被後面的覆蓋。
2、登入 shell 與 非登入 shell
1)登入 shell
在任何時候,如通過ssh連線登入到遠端主機,或者使用
登入 shell 的初始化會執行登入檔案(.profile)與環境檔案(.bashrc)。
2)非登入 shell
當開啟一個 shell 視窗不需要登入認證時,如在一個已登入的 shell 視窗輸入 bash
開啟一個新 shell,或者在桌面環境簡單地開啟一個終端視窗,等,我們稱這類 shell 為 非登入 shell。
非登入 shell 只執行環境檔案。
3、初始化檔案內容
shell 的初始化檔案一般包含下述內容:
1)建立或者修改環境變數的命令
2)執行所有一次性操作的命令
3)合理的註釋
4)等
如:
# 設定環境變數
HISTSIZE=50
HISTFILESIZE=1000
# 設定檔案建立掩碼,控制新建立檔案的預設許可權
umask 077
# 設定別名
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# 設定預設的分頁程式(需要呼叫分頁程式顯示資料時就會呼叫該程式,如 man 命令)
export PAGER=less
# 設定分頁程式的預設選項,相當於:alias less='less -CMs'
export LESS='-CMs'
# 檢視命名為`.bashrc`的檔案是否存在,如果存在,則執行這個檔案
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
十、參考
書箱:《Unix & Linux 大學教程》第11-14章 (美)Harley Hahn 著 張傑良 譯
部落格: 命令列介面 (CLI)、終端 (Terminal)、Shell、TTY的區別
SegmentFault: Linux TTY/PTS概述