Linux系統學習筆記:shell環境
Linux系統中包含強大的shell環境,作為命令解釋器。通過shell環境不僅可以和大量的命令行工具進行交互,而且shell還支持腳本編程,以批處理的方式完成更為復雜耗時的工作。BASH是目前絕大多數Linux版本的默認shell解釋器。本篇我們以BASH為基礎總結shell環境。
在文本界面或者圖形界面的終端模擬窗口中,shell作為命令解釋器運行,稱為shell環境。有多個版本的shell,通常BASH用的較多。
BASH通過 /etc/profile 文件進行全局配置。登錄時,會查找並執行 ~/.bash_profile 、 ~/.bash_login、 ~/.profile ,注銷時執行 ~/.bash_logout 。非登錄還會執行 /etc/bashrc 和 ~/.bashrc 文件。非交互的BASH不執行這些初始化文件中的命令,只繼承它們設置的變量,並且執行 BASH_ENV 環境變量指定的文件中的命令。
一般需要修改默認的環境變量時,在profile文件( ~/.bash_profile 、 ~/.profile 、 /etc/profile )中修改。而命令如命令別名在rc文件( ~/.bashrc 、 /etc/bash.bashrc )中修改。
shell命令在鍵入回車之後執行,在此之前可以修改。
下面是shell環境中一些鍵的作用:
Backspace Delete ^H 刪除字符
^W 刪除單詞
^U 刪除行
^C 中斷
^Z 掛起
^D 退出當前用戶登錄
shell中輸入的命令的語法是:
cmd [arg] ... [arg]
通常開始為命令名,後面接可選的參數。以 - 或 -- 開頭的參數也稱為選項,一般放在普通的參數之前,由命令解釋, - 開頭的選項通常可以合並。可以使用 -- 來表示後面的參數不解釋為選項。
shell在 PATH 環境變量指定的路徑下查找用戶擁有執行權限的程序。
shell中的特殊字符包括:
` ! # $ % ^ & * + ~ \ | ; ' " / ? < > ( ) [ ] { }
在特殊字符前加上 \ 可以對特殊字符進行轉義,也可以通過使用單引號將它們括起來。輸入控制字符可以先按 ^V 。
; 號可以分隔多條命令,但不立即執行它們。對於單條命令過長時,可以使用 \ 換到下一行繼續輸入。 ()可以對命令分組,shell為每組命令創建一個子shell,把它們作為一個作業。
# 開始行注釋。 && 和 || 為邏輯與和邏輯或,連接命令可以做短路判斷。 ! 反轉命令的退出狀態值。
此外, . 在行首時執行命令。
重定向
一個程序的進程會打開3個文件描述符,分別是標准輸入(0)、標准輸出(1)和標准錯誤輸出(2)。一般情況下,標准輸入是鍵盤,標准輸出和標准錯誤輸出是shell輸出,可以通過重定向來改變標准輸入輸出的關聯。 < 重定向標准輸入( 0< 的簡寫), > 重定向標准輸出( 1> 的簡寫), 2> 重定向標准錯誤輸出, >> 將標准輸出追加到文件, << 將腳本的內容重定向為腳本的輸入。
<< 重定向的內容稱為Here文檔,使用一個或多個符號來界定,開頭的界定符必須緊挨 << ,結尾的界定符必須獨占一行。
重定向會覆蓋已有文件,可以設置 noclobber 來禁止重定向時重寫,而 >| 則可以忽略 noclobber 設置。
/dev/null 稱為位桶,可以將標准輸出重定向到 /dev/null 來拋棄輸出的內容。
$ set -o noclobber
$ date --rfc-3339=seconds > d.txt
$ cat d.txt
2012-03-08 16:55:46+08:00
$ date --rfc-3339=seconds > d.txt
-bash: d.txt: cannot overwrite existing file
$ date --rfc-3339=seconds >| d.txt
$ cat d.txt
2012-03-08 16:56:00+08:00
$ set +o noclobber
$ date --rfc-3339=seconds > d.txt
$ cat d.txt
2012-03-08 16:56:31+08:00
$ date --rfc-3339=seconds >> d.txt
$ cat d.txt
2012-03-08 16:56:31+08:00
2012-03-08 16:57:14+08:00
$ cat /dev/null > d.txt # 刪除文件內容
$ grep -i alex <<+
> Alex
> Harry
> Nancy
> +
Alex
可以用 &n 代替重定向到的文件名, n 為文件描述符。重定向到 &- 表示關閉該描述符。
$ cat a
file a
$ cat b
cat: b: No such file or directory
$ cat a b > out # 重定向標准輸出到out
cat: b: No such file or directory
$ cat out
file a
$ cat a b 1> out 2>&1 # 重定向標准輸出到out,重定向標准錯誤輸出到標准輸出(即out)
$ cat out
file a
cat: b: No such file or directory
$ cat a b 2>&1 1> out # 重定向標准錯誤輸出到標准輸出,重定向標准輸出到out
cat: b: No such file or directory
$ cat out
file a
管道
shell環境下的管道可以將前一個命令的輸出作為後一個命令的輸入,管道實際上並不單獨處理每條命令,而且不產生中間文件。語法為:
cmd [args] | cmd [args]
管道可以串聯,也可以和重定向組合使用。
$ who | tee w.out | grep yeolar # 還生成了包含全部登錄用戶的w.out文件
yeolar pts/2 2012-03-08 16:13 (yeolar-pc.local)
tee 命令可以將標准輸入復制到標准輸出和文件。
後台運行
命令默認在前台運行,在命令執行完畢後將控制權交回shell。可以讓命令在後台運行,這樣可以不必等待命令執行完畢。命令或管道連接的命令序列稱為作業,可以有多個作業在後台運行。同一時間運行多個作業稱為多任務特性。
在命令行末尾加上 & 可以使作業在後台運行。shell會給作業分配一個作業編號。 jobs 顯示作業的列表。使用 fg 命令(或 % )可以將後台作業移到前台,使用 bg 命令可以將掛起的作業移到後台運行。
$ cat & # 後台運行cat,作業號1,PID 2640;掛起sleep,作業號2
[1] 2640
$ sleep 10
^Z
[1]- Stopped cat
[2]+ Stopped sleep 10
$ date --rfc-3339=s
2012-03-09 09:07:17+08:00
$ date --rfc-3339=s # 等待超過10s
2012-03-09 09:07:32+08:00
$ bg # sleep作業仍在,移到後台並運行
[2]+ sleep 10 &
$ jobs # 顯示作業列表,sleep因為超時而結束
[1]+ Stopped cat
[2]- Done sleep 10
$ %1 # 將作業1移到前台;掛起cat,作業號1
cat
^Z
[1]+ Stopped cat
$ bg 1 # 將作業1移到後台
[1]+ cat &
$ jobs # 顯示作業列表
[1]+ Stopped cat
$ fg # 將作業1移到前台;中斷cat
cat
^C
目錄棧
dirs 命令顯示目錄棧, pushd 改變目錄,並將目錄壓入目錄棧,不加參數時交換棧頂的兩個目錄, popd將目錄從棧中彈出,不加參數時彈出棧頂目錄,並改變到該目錄。
$ mkdir -p a/b/c
$ dirs
~
$ pushd a/
~/a ~
$ pushd b/c/ # pwd:~/a
~/a/b/c ~/a ~
$ pushd # pwd:~/a/b/c
~/a ~/a/b/c ~
$ pushd b/ # pwd:~/a
~/a/b ~/a ~/a/b/c ~
$ pushd +1 # pwd:~/a/b
~/a ~/a/b/c ~ ~/a/b
$ popd +1 # pwd:~/a
~/a ~ ~/a/b
$ popd # pwd:~/a
~ ~/a/b
$ popd +1
~
命令歷史
HISTSIZE 、 HISTFILE 和 HISTFILESIZE 可以設置命令歷史的保存數量和文件。
fc 命令可以查看( -l )、編輯(無參數或 -e )、重新執行( -s )命令。
還可以用 ! 引用事件(即命令):
!! 執行前一個命令
!n 執行歷史列表編號為n的命令,n為負值時,執行最近第|n|條命令
!str 執行最近以str開頭的命令
!?str[?] 執行最近包含str的命令,後面的?是可選的
!# 當前命令已經輸入的部分
!{event} {}將event和左右文本隔開
命令可以使用字標志符和修飾符進行一些修改和替換等。
Readline庫
BASH的命令行編輯是通過Readline庫實現的。有vi和emacs兩種編輯模式可選。命令行的諸如命令行補全和一些快捷鍵功能都是源於Readline庫。
別名
BASH的另一個很方便的功能是別名,通過 alias 將命令簡化。 alias 可以嵌套。一般會在BASH的rc配置文件中配置它。
$ alias
alias ls='ls --color=auto'
$ alias ll='ls -l'
擴展
{}擴展
{} 中以 , 分隔開的字符串會擴展成以空格符分開的字符串列表, {} 兩端可以有可選的前綴和後綴,它們被加到字符串列表中每個字符串的兩端。
$ touch a{1,2,3,4,5}.txt
$ ls
a1.txt a2.txt a3.txt a4.txt a5.txt
~擴展
~ 代替 HOME 變量的值。如果 ~ 後面跟一個合法的用戶名,那就會替換為該用戶的主目錄。在目錄棧中, ~+為當前工作目錄, ~- 為前一個工作目錄。
$ echo ~root
/root
算術擴展
$((expr)) 會計算 expr 並用結果替代它。BASH中使用整數進行計算。在 $(()) 中變量的引用符 $ 可以省略。 let 命令也計算算術表達式的值,而且可以給它傳遞多個參數。
$ x=3 y=7; echo $(((x+y)/2))
5
$ let m=(x+y)/2 n=(x+y)/m; echo $m $n
5 2
命令替換
命令替換的語法有兩種: $(cmd) 和 `cmd` ,它們用命令的輸出替代該命令。
$ ls -l $(find . -name README -print)
路徑擴展
對於包含特殊字符的文件名,shell可以生成和已有文件的名字匹配的文件名,這稱為路徑擴展或通配,特殊字符稱為通配符。
? 匹配單個字符, * 匹配0或多個字符, [] 匹配方括號中的任意一個字符,可以用 - 指定字符范圍,還可以在字符列表前用 ! 或 ^ 表示不匹配任意一個字符。
$ touch a111 a1 a2 a3 a5 b2 b3 c5
$ echo *
a1 a111 a2 a3 a5 b2 b3 c5
$ echo .*
. ..
$ echo a*
a1 a111 a2 a3 a5
$ echo a?
a1 a2 a3 a5
$ echo a[1-3]
a1 a2 a3
$ echo a[!1-3]
a5
$ echo a[^1-3]
a5
$ echo [a-z]*
a1 a111 a2 a3 a5 b2 b3 c5
$ echo [a-z]?
a1 a2 a3 a5 b2 b3 c5
變量
shell變量以字母(包括 _ )和數字組成,以字母開頭。全局變量又稱環境變量,通常采用大寫形式。使用= 號創建變量, = 兩邊沒有空格。變量值默認以字符串形式保存。在變量名前加上 $ 來引用變量,可以在變量名兩邊加上 {} 來消除歧義。
賦值語句 = 右側為空可以將值置空, unset 命令刪除變量。
單引號和雙引號將內容解釋為字符串,單引號會阻止引用。
$ fa=a*
$ echo fa
fa
$ echo $fa
a1 a2 a3
$ echo ${fa}a
a*a
$ echo "$fa"
a*
$ echo '$fa'
$fa
可以使用 declare 或 typeset 設置變量屬性,有以下選項:
-a 聲明數組變量
-f 聲明函數變量
-i 聲明整型變量
-r 聲明只讀變量,等價於 readonly
-x 輸出變量(設置為全局變量),等價於 export
如果將選項的前導 - 改為 + ,可以刪除特定屬性。不帶參數時,列出所有特定類或全部的變量。
關鍵字變量
HOME 變量保存用戶主目錄, ~ 會被shell展開為 HOME 值。
PATH 指定了shell的搜索路徑,搜索路徑由 : 分隔的一組路徑組成。 export PATH 會使其可被子shell訪問。
$ export PATH=$PATH:$HOME: # 中間的:也可省略
CDPATH 和 PATH 語法類似,它擴展了 cd 命令可進入目錄的范圍。
PS1 設置用戶主提示符, PS2 設置用戶次提示符,默認為 > , PS3 設置 select 控制結構的菜單提示符,PS4 設置BASH調試提示符。
IFS 設置分詞的分隔符,默認為空白符,通常不需要對其進行修改。
更多的關鍵字變量可以參考 man bash 手冊。
函數
函數也是一種變量,創建函數的語法為:
[function ]name ()
{
command
}
函數將一組命令放在一起,方便了調用。函數名和命令一樣,執行函數只需執行函數名即可。
可以把常用的函數放在BASH的profile文件中。
shell特性
可以使用 set -o 和 set +o 開啟和關閉shell的特性。BASH的特性參看 man bash 。