天天看點

Shell常用指令SHELL

SHELL

常見的Shell

檢視shell

目前 Linux 系統可用的 Shell 都記錄在

/etc/shells

檔案中。

/etc/shells

是一個純文字檔案

$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
           

在現代的 Linux 上,sh 已經被 bash 代替,

/bin/sh

往往是指向

/bin/bash

的符号連結

如果你希望檢視目前 Linux 的預設 Shell,那麼可以輸出 SHELL 環境變量:

$ echo $SHELL
/bin/bash
           

shell提示符

對于普通使用者,Base shell 預設的提示符是美元符号

$

;對于超級使用者(root 使用者),Bash Shell 預設的提示符是井号

#

。該符号表示 Shell 等待輸入指令

Shell 通過

PS1

PS2

兩個環境變量來控制提示符格式:

  • PS1 控制最外層指令行的提示符格式。
  • PS2 控制第二層指令行的提示符格式。

要顯示提示符的目前格式,可以使用 echo 輸出 PS1 和 PS2:

[[email protected] ~]$ echo $PS1
[\[email protected]\h \W]\$
[[email protected] ~]$ echo $PS2
>
           

Shell 使用以

\

為前導的特殊字元來表示指令提示符中包含的要素,這使得 PS1 和 PS2 的格式看起來可能有點奇怪。下表展示了可以在 PS1 和 PS2 中使用的特殊字元。

字元 描述
\a 鈴聲字元
\d 格式為“日 月 年”的日期
\e ASCII轉義字元
\h 本地主機名
\H 完全合格的限定域主機名
\j shell目前管理的作業數
\1 shell終端裝置名的基本名稱
\n ASCII換行字元
\r ASCII回車
\s shell的名稱
\t 格式為“小時:分鐘:秒”的24小時制的目前時間
\T 格式為“小時:分鐘:秒”的12小時制的目前時間
@ 格式為am/pm的12小時制的目前時間
\u 目前使用者的使用者名
\v bash shell的版本
\V bash shell的釋出級别
\w 目前工作目錄
\W 目前工作目錄的基本名稱
! 該指令的bash shell曆史數
# 該指令的指令數量
$ 如果是普通使用者,則為美元符号

$

;如果超級使用者(root 使用者),則為井号

#

\nnn 對應于八進制值 nnn 的字元
\ 斜杠
[ 控制碼序列的開頭
] 控制碼序列的結尾

注意,所有的特殊字元均以反斜杠

\

開頭,目的是與普通字元區分開來。您可以在指令提示符中使用以上任何特殊字元的組合。我們可以通過修改 PS1 變量來修改提示符格式,例如:

[[email protected] ~]$ PS1="[\t][\u]\$ "[17:27:34][mozhiyan]$ 
           

新的 Shell 提示符現在可以顯示目前的時間和使用者名。不過這個新定義的 PS1 變量隻在目前 Shell 會話期間有效,再次啟動 Shell 時将重新使用預設的提示符格式

First Shell腳本

打開文本編輯器,建立一個文本檔案,并命名為 test.sh。

擴充名

sh

代表 shell,擴充名并不影響腳本執行,見名知意就好,如果你用 php 寫 shell 腳本,擴充名就用

php

好了

在 test.sh 中輸入代碼:

#!/bin/bash
echo "Hello World !"  #這是一條語句
           

第 1 行的

#!

是一個約定的标記,它告訴系統這個腳本需要什麼解釋器來執行,即使用哪一種Shell;後面的

/bin/bash

就是指明了解釋器的具體位置。

第 2 行的 echo 指令用于向标準輸出檔案(Standard Output,stdout,一般就是指終端)輸出文本。在

.sh

檔案中使用指令與在終端直接輸入指令的效果是一樣的。

第 2 行的

#

及其後面的内容是注釋。Shell 腳本中所有以

#

開頭的都是注釋(當然以

#!

開頭的除外)。寫腳本的時候,多寫注釋是非常有必要的,以友善其他人能看懂你的腳本,也友善後期自己維護時看懂自己的腳本——實際上,即便是自己寫的腳本,在經過一段時間後也很容易忘記。

下面給出了一段稍微複雜的 Shell 腳本:

#!/bin/bash
# Copyright (c) http://c.biancheng.net/shell/
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"
           

第 5 行中表示從終端讀取使用者輸入的資料,并指派給 PERSON 變量。read 指令用來從标準輸入檔案(Standard Input,stdin,一般就是指終端)讀取使用者輸入的資料。

第 6 行表示輸出變量 PERSON 的内容。注意在變量名前邊要加上

$

,否則變量名會作為字元串的一部分處理。

執行shell腳本方法

作為可執行程式

Shell 腳本也是一種解釋執行的程式,可以在終端直接調用(需要使用 chmod 指令給 Shell 腳本加上執行權限),如下所示:

$ cd demo  #切換到 test.sh 所在的目錄
$ chmod +x ./test.sh  #使腳本具有執行權限
$ ./test.sh  #執行腳本
           

第 2 行中,

chmod +x

表示給 test.sh 增加執行權限。

第 3 行中,

./

表示目前目錄,整條指令的意思是執行目前目錄下的 test.sh 腳本。如果不寫

./

,Linux會到系統路徑(由 PATH 環境變量指定)下查找 test.sh,而系統路徑下顯然不存在這個腳本,是以會執行失敗。

通過這種方式運作腳本,第一行一定要寫對,好讓系統查找到正确的解釋器。

1) 使用點号

.

點号用于執行某個腳本,甚至腳本沒有可執行權限也可以運作。有時候在測試運作某個腳本時可能并不想為此修改腳本權限,這時候就可以使用

.

來運作腳本,非常友善。

如果沒有運作權限的話,用

./

執行就會有報錯,但是若在其前面使用點号來執行就不會報錯

$ . ./test.sh  #注意 兩個 . 之間有空格
           

2) 使用 source 指令

與點号類似,source 指令也可讀取并在目前環境中執行腳本,同時還可傳回腳本中最後一個指令的傳回狀态;如果沒有傳回值則傳回 0,代表執行成功;如果未找到指定的腳本則傳回 false。

$ source test.sh
           

作為解釋器參數

這種運作方式是,直接運作解釋器,其參數就是 shell 腳本的檔案名,如:

$ /bin/bash test.sh
http://c.biancheng.net/shell/
           

這種方式運作的腳本,不需要在第一行指定解釋器資訊,寫了也沒用

安裝Bash Shell

安裝步驟

定義變量

三種聲明方式

variable=value
variable='value'
variable="value"
           

注意,指派号

=

的周圍不能有空格,這可能和你熟悉的大部分程式設計語言都不一樣

三者的差別

  • 如果 value 不包含任何空白符(例如空格、Tab 縮進等),那麼可以不使用引号
  • 以單引号

    ' '

    包圍變量的值時,單引号裡面是什麼就輸出什麼,即使内容中有變量和指令(指令需要反引起來)也會把它們原樣輸出。這種方式比較适合定義顯示純字元串的情況,即不希望解析變量、指令等的場景。
  • 以雙引号

    " "

    包圍變量的值時,輸出時會先解析裡面的變量和指令,而不是把雙引号中的變量名和指令原樣輸出。這種方式比較适合字元串中附帶有變量和指令并且想将其解析後再輸出的變量定義。

兩種使用方式

echo $variable
echo ${variable}
#下面這種情況,需要加{},否則解釋器就會把 $skillScript 當成一個變量(其值為空)
echo "I am good at ${skill}Script"
           

加花括号是為了幫助解釋器識别變量的邊界,推薦給所有變量加上花括号

{}

隻讀變量

使用

readonly

指令可以将變量定義為隻讀變量,隻讀變量的值不能被改變

#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl
#下面這一行會報錯:zsh: read-only variable: myUrl
myUrl="http://see.xidian.edu.cn/cpp/danpianji/"
           

删除變量

使用

unset

指令可以删除變量。文法:

unset variable_name
           

變量被删除後不能再次使用;unset 指令不能删除隻讀變量

變量作用域

一共三種作用域

全局變量

所謂全局變量,就是指變量在目前的整個 Shell 會話中都有效。每個 Shell 會話都有自己的作用域,彼此之間互不影響。在 Shell 中定義的變量,預設就是全局變量

需要強調的是,全局變量的作用範圍是目前的 Shell 會話,而不是目前的 Shell 腳本檔案,它們是不同的概念。打開一個 Shell 視窗就建立了一個 Shell 會話,打開多個 Shell 視窗就建立了多個 Shell 會話,每個 Shell 會話都是獨立的程序,擁有不同的程序 ID。在一個 Shell 會話中,可以執行多個 Shell 腳本檔案,此時全局變量在這些腳本檔案中都有效

局部變量

Shell 也支援自定義函數,但是 Shell 函數和 C/C++、Java 等其他程式設計語言函數的一個不同點就是:在 Shell 函數中定義的變量預設也是全局變量,它和在函數外部定義變量擁有一樣的效果

要想變量的作用域僅限于函數内部,那麼可以在定義時加上

local

指令,此時該變量就成了局部變量

#!/bin/bash
#定義函數
function func(){
    local a=99
}
#調用函數
func
#輸出函數内部的變量
echo $a
           

輸出結果為空,表明變量 a 在函數外部無效,是一個局部變量。

Shell 變量的這個特性和 JavaScript 中的變量是類似的。在 JavaScript 函數内部定義的變量,預設也是全局變量,隻有加上

var

關鍵字,它才會變成局部變量

環境變量

使用

export

指令将它導出,它就在所有的子 Shell 中也有效了

環境變量被建立時所處的 Shell 被稱為父 Shell,如果在父 Shell 中再建立一個 Shell,則該 Shell 被稱作子 Shell。當子 Shell 産生時,它會繼承父 Shell 的環境變量為自己所用,是以說環境變量可從父 Shell 傳給子 Shell。不難了解,環境變量還可以傳遞給孫 Shell。

注意,環境變量隻能向下傳遞而不能向上傳遞,即“傳子不傳父”。

在一個 Shell 中建立子 Shell 最簡單的方式是運作 bash 指令

通過

exit

指令可以一層一層地退出 Shell

export a

這種形式是在定義變量 a 以後再将它導出為環境變量,如果想在定義的同時導出為環境變量,可以寫作

export a=22

如果想讓環境變量在所有 Shell 中都有效,并且能夠永久儲存,在關閉 Shell 後也不丢失,那麼就需要把環境變量寫入啟動檔案

位置參數(指令行參數)

運作 Shell 腳本檔案時我們可以給它傳遞一些參數,這些參數在腳本檔案内部可以使用

$n

的形式來接收,例如,

$1

表示第一個參數,

$2

表示第二個參數,依次類推。

同樣,在調用函數時也可以傳遞參數。Shell 函數參數的傳遞和其它程式設計語言不同,沒有所謂的形參和實參,在定義函數時也不用指明參數的名字和數目。換句話說,定義 Shell 函數時不能帶參數,但是在調用函數時卻可以傳遞參數,這些傳遞進來的參數,在函數内部就也使用

$n

的形式接收,例如,

$1

表示第一個參數,

$2

表示第二個參數,依次類推。

這種通過

$n

的形式來接收的參數,在 Shell 中稱為位置參數

  • 給腳本檔案傳遞位置參數

    #!/bin/bash
    echo "Language: $1"
    echo "URL: $2"
               
    $ . ./a.sh Shell http://c.biancheng.net/shell/
               
  • 給函數傳遞位置參數

#!/bin/bash
#定義函數
function func(){
    echo "Language: $1"
    echo "URL: $2"
}
#調用函數
func C++ http://c.biancheng.net/cplus/
           

特殊變量

變量 含義
$0 目前腳本的檔案名。
$n(n≥1) 傳遞給腳本或函數的參數。n 是一個數字,表示第幾個參數。例如,第一個參數是

$1

,第二個參數是

$2

$# 傳遞給腳本或函數的參數個數。${#str} 可以擷取str字元串長度
$* 傳遞給腳本或函數的所有參數。
[email protected] 傳遞給腳本或函數的所有參數。當被雙引号

" "

包含時,[email protected] 與 $* 稍有不同,我們将在《Shell ∗ 和 *和 ∗和@的差別》一節中詳細講解。
$? 上個指令的退出狀态,或函數的傳回值,我們将在《Shell $?》一節中詳細講解。
$$ 目前 Shell 程序 ID。對于 Shell 腳本,就是這些腳本所在的程序 ID。

$*

[email protected]

的差別

當 $* 和 [email protected] 不被雙引号

" "

包圍時,它們之間沒有任何差別,都是将接收到的每個參數看做一份資料,彼此之間以空格來分隔。但是當它們被雙引号

" "

包含時,就會有差別了:

  • "$*"

    會将所有的參數從整體上看做一份資料,而不是把每個參數都看做一份資料。
  • "[email protected]"

    仍然将每個參數都看作一份資料,彼此之間是獨立的。 注:可以分割用于for循環

$?

:擷取函數傳回值或上一個指令的退出狀态

  • 擷取上一個指令的退出狀态

    a.sh

    #!/bin/bash
    if [ $1 == 100 ]
    then
       return 0  #參數正确,傳回0
    else
       return 1  #參數錯誤,傳回1
    fi
               
    b.sh
    #!/bin/bash
    echo $?
               
    結果:
    $ . ./a.sh 100
    $ . ./b.sh
    0
               
  • 擷取函數傳回值

    test.sh

    #!/bin/bash
    #得到兩個數相加的和
    function add(){
        return `expr $1 + $2`
    }
    add 23 50  #調用函數
    echo $?  #擷取函數傳回值
               
    結果:
    $ . ./test.sh
    73
               

字元串截取

指定位置截取

  • 從左向右
    #${string: start :length}
    #string 是要截取的字元串,start 是起始位置(從左邊開始,從 0 開始計數),length 是要截取的長度(省略的話表示直到字元串的末尾)
    url="c.biancheng.net"
    echo ${url: 2: 9}
    echo ${url: 2}  #省略 length,截取到字元串末尾
               
  • 從右向左

    從右邊開始計數時,起始數字是 1。不管從哪邊開始計數,截取方向都是從左到右

    #${string: 0-start :length}
    url="c.biancheng.net"
    echo ${url: 0-13: 9}
    #上面的結果為biancheng。從右邊數,b是第 13 個字元
    url="c.biancheng.net"
    echo ${url: 0-13}  #省略 length,直接截取到字元串末尾
               

從指定字元(子字元串)開始截取

  • 使用 # 号截取右邊字元

#使用#号可以截取指定字元(或者子字元串)右邊的所有字元
${string#*chars}
#示例
url="http://c.biancheng.net/index.html"
echo ${url#*:}
#結果為//c.biancheng.net/index.html

#如果希望直到最後一個指定字元(子字元串)再比對結束,那麼可以使用##
${string##*chars}
           

其中,string 表示要截取的字元,chars 是指定的字元(或者子字元串),

*

是通配符的一種,表示任意長度的字元串。

*chars

連起來使用的意思是:忽略左邊的所有字元,直到遇見 chars(chars 不會被截取

  • 使用 % 截取左邊字元

    #注意*的位置,因為要截取 chars 左邊的字元,而忽略 chars 右邊的字元,是以*應該位于 chars 的右側。其他方面%和#的用法相同
    ${string%chars*}
               
  • 彙總
    格式 說明
    ${string: start :length} 從 string 字元串的左邊第 start 個字元開始,向右截取 length 個字元。
    ${string: start} 從 string 字元串的左邊第 start 個字元開始截取,直到最後。
    ${string: 0-start :length} 從 string 字元串的右邊第 start 個字元開始,向右截取 length 個字元。
    ${string: 0-start} 從 string 字元串的右邊第 start 個字元開始截取,直到最後。
    ${string#*chars} 從 string 字元串第一次出現 *chars 的位置開始,截取 *chars 右邊的所有字元。
    ${string##*chars} 從 string 字元串最後一次出現 *chars 的位置開始,截取 *chars 右邊的所有字元。
    ${string%*chars} 從 string 字元串第一次出現 *chars 的位置開始,截取 *chars 左邊的所有字元。
    ${string%%*chars} 從 string 字元串最後一次出現 *chars 的位置開始,截取 *chars 左邊的所有字元。

數組

數組定義

Shell 是弱類型的,它并不要求所有數組元素的類型必須相同

Shell 數組元素的下标也是從 0 開始計數

array_name=(ele1  ele2  ele3 ... elen)
#下面的ages隻給第 3、5、10 個元素指派,是以數組長度是 3
ages=([3]=24 [5]=19 [10]=12)
           

擷取數組元素

#其中,array_name 是數組名,index 是下标
${array_name[index]}
           

使用

@

*

可以擷取數組中的所有元素

${nums[*]}
${nums[@]}
           

擷取數組長度

利用

@

*

,可以将數組擴充成清單,然後使用

#

來擷取數組元素的個數

${#array_name[@]}
${#array_name[*]}
           

如果某個元素是字元串,還可以通過指定下标的方式獲得該元素的長度

${#arr[2]}
           

數組拼接

拼接數組的思路是:先利用

@

*

,将數組擴充成清單,然後再合并到一起

array_new=(${array1[@]}  ${array2[@]})
array_new=(${array1[*]}  ${array2[*]})
           

删除

#删除某個元素
unset array_name[index]
#删除整個數組
unset array_name
#array_name 表示數組名,index 表示數組下标
           

内建指令

alias

#檢視目前存在的别名清單
$ alias
#添加别名,目前shell有效
$ alias myShutdown='shutdown -h now'
#為了確定永遠生效,可以将該别名手動寫入到使用者主目錄中的.bashrc

#删除所有别名,目前shell有效
$ unalias -a
#删除指定别名,目前shell有效
$ unalias 别名名字
#要想永久删除在.bashrc檔案中定義的别名,隻能進入該檔案手動删除
           

内建指令

echo

echo 指令輸出結束後預設會換行,如果不希望換行,可以加上

-n

參數

name="Tom"
height=175
weight=62
echo -n "${name} is years old, "
echo -n "${height}cm in height "
echo "and ${weight}kg in weight."
           

預設情況下,echo 不會解析以反斜杠

\

開頭的轉義字元。比如,

\n

表示換行,echo 預設會将它作為普通字元

我們可以添加

-e

參數來讓 echo 指令解析轉義字元

[[email protected] ~]# echo -e "hello \nworld"
hello
world
           

有了

-e

參數,我們也可以使用轉義字元

\c

來強制 echo 指令不換行了

#!/bin/bash
name="Tom"
weight=62
echo -e "${name}  years old, \c"
echo "and ${weight}kg in weight."
           

内建指令

exit

  • 如果在終端中直接運作 exit 指令,會退出目前登入的 Shell,并關閉終端;
  • 如果在 Shell 腳本中出現 exit 指令,會停止執行後邊的所有代碼,立即退出 Shell 腳本
  • exit 指令可以接受的參數是一個狀态值 n,代表退出時的狀态。如果不指定,預設狀态值是 0
    #!/bin/bash
    echo "befor exit"
    exit 8
    echo "after exit"
               
    我們可以緊接着使用

    $?

    來擷取 demo.sh 的退出狀态
    [[email protected] ~]# echo $?
    8
               

内建指令

ulimit

預設情況下 Linux 系統的各個資源都做了軟硬限制,其中硬限制的作用是控制軟限制(換言之,軟限制不能高于硬限制)。使用

ulimit -a

可以檢視目前系統的軟限制,使用指令

ulimit -a –H

可檢視系統的硬限制

[[email protected] ~]# ulimit -a
#core檔案大小,機關是block,預設為0
core file size          (blocks, -c) 0
#資料段大小,機關是kbyte,預設不做限制
data seg size           (kbytes, -d) unlimited
#排程優先級,預設為0
scheduling priority             (-e) 0
#建立檔案的大小,機關是block,預設不做限制
file size               (blocks, -f) unlimited
#挂起的信号數量,預設是8192
pending signals                 (-i) 8192
#最大鎖定記憶體的值,機關是kbyte,預設是32
max locked memory       (kbytes, -l) 32
#最大可用的常駐記憶體值,機關是kbyte,預設不做限制
max memory size         (kbytes, -m) unlimited
#最大打開的檔案數,預設是1024
open files                      (-n) 1024
#管道最大緩沖區的值
pipe size            (512 bytes, -p) 8
#消息隊列的最大值,機關是byte
POSIX message queues     (bytes, -q) 819200
#程式的實時性優先級,預設為0
real-time priority              (-r) 0
#棧大小,機關是kbyte
stack size              (kbytes, -s) 10240
#最大cpu占用時間,預設不做限制
cpu time               (seconds, -t) unlimited
#使用者最大程序數,預設是8192
max user processes              (-u) 8192
#最大虛拟記憶體,機關是kbyte,預設不做限制
virtual memory          (kbytes, -v) unlimited
#檔案鎖,預設不做限制
file locks                      (-x) unlimited
           

每一行中都包含了相應的改變該項設定的參數,以最大可以打開的檔案數為例(open files 預設是 1024),想要增大至 4096 則按照如下指令設定(可參照此方法調整其他參數)

#設定最大打開的檔案數
#該指令會同時設定硬限制和軟限制
[[email protected] ~]# ulimit -n 4096
#使用-S參數單獨設定軟限制
#[[email protected] ~]# ulimit -S -n 4096
#使用-H參數單獨設定硬限制
#[[email protected] ~]# ulimit -H -n 4096
           

使用 ulimit 直接調整參數,隻會在目前運作時生效,一旦系統重新開機,所有調整過的參數就會變回系統預設值。是以建議将所有的改動放在 ulimit 的系統配置檔案中

[[email protected] ~]# cat /etc/security/limits.conf
# /etc/security/limits.conf
#該檔案是ulimit的配置檔案,任何對系統的ulimit的修改都應該寫入該檔案
#請将所有的設定寫到該檔案的最後
#Each line describes a limit for a user in the form:
#配置應該寫成下面這行的格式,即每個配置占用1行,每行4列
#每列分别是<domain> <type> <item> <value>
#<domain>        <type>  <item>  <value>
#
#其中:
#<domain>可以取的值如下:
#       - 一個使用者名
#       - 一個組名,組名前面用@符号
#       - 通配符*
#       - 通配符%
#Where:
#<domain> can be:
#        - an user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#
#<type>隻有以下兩個可用值:
#       - soft用于設定軟限制
#       - hard用于設定硬限制
#<type> can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
#<item>的值可以是以下任意一種:
#        - core - core檔案大小的限制 (KB)
#        - data - 最大資料段限制 (KB)
#        - fsize - 最大檔案大小 (KB)
#        - memlock - 最大鎖定的記憶體大小 (KB)
#        - nofile - 最大打開檔案數
#        - rss - 最大常駐記憶體值 (KB)
#        - stack - 最大棧空間大小 (KB)
#        - cpu - 最大CPU使用時間 (MIN)
#        - nproc - 最大程序數
#        - as - 虛拟位址空間
#        - maxlogins - 某使用者的最大登入數
#        - maxsyslogins - 系統使用者最大登入數
#        - priority - 使用者程序的運作優先級
#        - locks – 使用者最大可以鎖定檔案的數量
#        - sigpending - 最大挂起的信号量數
#        - msgqueue - POSIX信号隊列使用的最大記憶體值 (bytes)
#        - nice - 最大nice值
#        - rtprio - 最大實時優先級
#
#<item> can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open files
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to
#        - rtprio - max realtime priority
#
#<domain>      <type>  <item>         <value>
#
#以下是使用樣例,請參照配置
#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4
           

内建指令

declare

declare [+/-] [aAfFgilprtux] [變量名=變量值]
           

其中,

-

表示設定屬性,

+

表示取消屬性,

aAfFgilprtux

都是具體的選項,它們的含義如下表所示

選項 含義
-f [name] 列出之前由使用者在腳本中定義的函數名稱和函數體。
-F [name] 僅列出自定義函數名稱。
-g name 在 Shell 函數内部建立全局變量。
-p [name] 顯示指定變量的屬性和值。
-a name 聲明變量為普通數組。
-A name 聲明變量為關聯數組(支援索引下标為字元串)。
-i name 将變量定義為整數型。
-r name[=value] 将變量定義為隻讀(不可修改和删除),等價于 readonly name。
-x name[=value] 将變量設定為環境變量,等價于 export name[=value]。

【執行個體1】将變量聲明為整數并進行計算

#!/bin/bash
declare -i m n ret  #将多個變量聲明為整數
m=10
n=30
ret=$m+$n
echo $ret
#運作結果:40
           

注意:除了将參與運算的變量定義為整數,還得将承載結果的變量定義為整數,而且隻能用整數類型的變量來承載運算結果,不能直接使用 echo 輸出。

和 (())、let、$[] 不同,

declare -i

的功能非常有限,僅支援最基本的數學運算(加減乘除和取餘),不支援邏輯運算(比較運算、與運算、或運算、非運算),是以在實際開發中很少使用

【執行個體2】将變量定義為隻讀變量

[c.biancheng.net]$ declare -r n=10
[c.biancheng.net]$ n=20
-bash: n: readonly variable
[c.biancheng.net]$ echo $n
10
           

【執行個體3】顯示變量的屬性和值

[c.biancheng.net]$ declare -r n=10
[c.biancheng.net]$ declare -p n
declare -r n="10"
           

指令替換:将指令輸出賦給變量

Shell 中有兩種方式可以完成指令替換,一種是反引号,一種是

$()

var_name=`command`
var_name=$(command)
           

如果被替換的指令的輸出内容包括多行(也即有換行符),或者含有多個連續的空白符,那麼在輸出變量時應該将變量用雙引号包圍,否則系統會使用預設的空白符來填充,這會導緻換行無效,以及連續的空白符被壓縮成一個.是以,為了防止出現格式混亂的情況,建議在輸出變量時加上雙引号

反引号和 $()差別

  • $() 支援嵌套
    [[email protected] ~]# Fir_File_Lines=$(wc -l $(ls | sed -n '1p'))
    [[email protected] ~]# echo "$Fir_File_Lines"
    36 anaconda-ks.cfg
               
  • $() 僅在 Bash Shell 中有效,而反引号可在多種 Shell 中使用

數學計算

常見的 Shell 算術運算符

算術運算符 說明/含義
+、- 加法(或正号)、減法(或負号)
*、/、% 乘法、除法、取餘(取模)
** 幂運算
++、– 自增和自減,可以放在變量的前面也可以放在變量的後面
!、&&、|| 邏輯非(取反)、邏輯與(and)、邏輯或(or)
<、<=、>、>= 比較符号(小于、小于等于、大于、大于等于)
==、!=、= 比較符号(相等、不相等;對于字元串,= 也可以表示相當于)
<<、>> 向左移位、向右移位
~、|、 &、^ 按位取反、按位或、按位與、按位異或
=、+=、-=、*=、/=、%= 指派運算符,例如 a+=1 相當于 a=a+1,a-=1 相當于 a=a-1

Shell 中常用的數學計算指令如下表

運算操作符/運算指令 說明
(( )) 用于整數運算,效率很高,推薦使用。
let 用于整數運算,和 (()) 類似。
[$] 用于整數運算,不如 (()) 靈活。
expr 可用于整數運算,也可以處理字元串。比較麻煩,需要注意各種細節,不推薦使用。
bc Linux下的一個電腦程式,可以處理整數和小數。Shell 本身隻支援整數運算,想計算小數就得使用 bc 這個外部的電腦。
declare -i 将變量定義為整數,然後再進行數學運算時就不會被當做字元串了。功能有限,僅支援最基本的數學運算(加減乘除和取餘),不支援邏輯運算、自增自減等,是以在實際開發中很少使用。

(()) : 整數運算

運算操作符/運算指令 說明
((a=10+66) ((b=a-15)) ((c=a+b)) 這種寫法可以在計算完成後給變量指派。以 ((b=a-15)) 為例,即将 a-15 的運算結果指派給變量 c。 注意,使用變量時不用加

$

字首,(( )) 會自動解析變量名。
a= ( ( 10 + 66 ) b = ((10+66) b= ((10+66)b=((a-15)) c=$((a+b)) 可以在 (( )) 前面加上

$

符号擷取 (( )) 指令的執行結果,也即擷取整個表達式的值。以 c= ( ( a + b ) ) 為 例 , 即 将 a + b 這 個 表 達 式 的 運 算 結 果 賦 值 給 變 量 c 。 注 意 , 類 似 c = ( ( a + b ) ) 這 樣 的 寫 法 是 錯 誤 的 , 不 加 ‘ ((a+b)) 為例,即将 a+b 這個表達式的運算結果指派給變量 c。 注意,類似 c=((a+b)) 這樣的寫法是錯誤的,不加` ((a+b))為例,即将a+b這個表達式的運算結果指派給變量c。注意,類似c=((a+b))這樣的寫法是錯誤的,不加‘`就不能取得表達式的結果。
((a>7 && b==c)) (( )) 也可以進行邏輯運算,在 if 語句中常會使用邏輯運算。
echo $((a+10)) 需要立接輸出表達式的運算結果時,可以在 (( )) 前面加

$

符号。
((a=3+5, b=a+10)) 對多個表達式同時進行計算。

let : 整數運算

和雙小括号 (( )) 一樣,let 指令也隻能進行整數運算,不能對小數(浮點數)或者字元串進行運算

let 表達式
#當表達式中含有 Shell 特殊字元(例如 |)時,需要用雙引号" "或者單引号' '将表達式包圍起來
           

和 (( )) 類似,let 指令也支援一次性計算多個表達式,并且以最後一個表達式的值作為整個 let 指令的執行結果。但是,對于多個表達式之間的分隔符,let 和 (( )) 是有差別的:

  • let 指令以空格來分隔多個表達式;
  • (( )) 以逗号

    ,

    來分隔多個表達式。

另外還要注意,對于類似

let x+y

這樣的寫法,Shell 雖然計算了 x+y 的值,但卻将結果丢棄;若不想這樣,可以使用

let sum=x+y

将 x+y 的結果儲存在變量 sum 中。

$[] : 整數計算

#$[] 會對表達式進行計算,并取得計算結果。如果表達式中包含了變量,那麼你可以加$,也可以不加
#需要注意的是,不能單獨使用 $[],必須能夠接收 $[] 的計算結果
$[表達式]
#示例
$ echo $[$m*$n]
           

expr

expr 是 evaluate expressions 的縮寫,譯為“表達式求值”。Shell expr 是一個功能強大,并且比較複雜的指令,它除了可以實作整數計算,還可以結合一些選項對字元串進行處理,例如計算字元串長度、字元串比較、字元串比對、字元串提取等。

expr 對

表達式
           

的格式有幾點特殊的要求:

  • 出現在

    表達式

    中的運算符、數字、變量和小括号的左右兩邊至少要有一個空格,否則會報錯。
  • 有些特殊符号必須用反斜杠

    \

    進行轉義(屏蔽其特殊含義),比如乘号

    *

    和小括号

    ()

    ,如果不用

    \

    轉義,那麼 Shell 會把它們誤解為正規表達式中的符号(

    *

    對應通配符,

    ()

    對應分組)。
  • 使用變量時要加

    $

    字首
[c.biancheng.net]$ m=5
[c.biancheng.net]$ n=`expr $m + 10`
[c.biancheng.net]$ echo $n
15

[c.biancheng.net]$ expr \( 2 + 3 \) \* 4  #使用 \ 轉義
           

bc : 電腦

Link : http://c.biancheng.net/view/2680.html

  • bc 指令選項
選項 說明
-h | --help 幫助資訊
-v | --version 顯示指令版本資訊
-l | --mathlib 使用标準數學庫
-i | --interactive 強制互動
-w | --warn 顯示 POSIX 的警告資訊
-s | --standard 使用 POSIX 标準來處理
-q | --quiet 不顯示歡迎資訊
  • bc 有四個内置變量
變量名 作 用
scale 指定精度,也即小數點後的位數;預設為 0,也即不使用小數部分。
ibase 指定輸入的數字的進制,預設為十進制。
obase 指定輸出的數字的進制,預設為十進制。
last 或者 . 表示最近列印的數字
  • 内置函數
s(x) 計算 x 的正弦值,x 是弧度值。
c(x) 計算 x 的餘弦值,x 是弧度值。
a(x) 計算 x 的反正切值,傳回弧度值。
l(x) 計算 x 的自然對數。
e(x) 求 e 的 x 次方。
j(n, x) 貝塞爾函數,計算從 n 到 x 的階數
  • 在 Shell 中使用 bc 電腦
$ echo "expression" | bc
$ variable=$(echo "expression" | bc)

[c.biancheng.net]$ echo "scale=5;n=$x+2;e(n)"|bc -l
403.42879

variable=$(bc << EOF
expressions
EOF
)
#其中,variable是 Shell 變量名,express是要計算的數學表達式(可以換行,和進入 bc 以後的書寫形式一樣),EOF是數學表達式的開始和結束辨別(你也可以換成其它的名字,比如 aaa、bbb 等)
           

if else

#demo
if  condition1
then
   statement1
elif condition2
then
    statement2
elif condition3
then
    statement3
……
else
   statementn
fi
           

内建指令

test

用法

$ test expression
#也可以簡寫為[],注意[]和expression之間的空格,這兩個空格是必須的,否則會導緻文法錯誤
$ [ expression ]
           

與檔案檢測相關的 test 選項

檔案類型判斷
選 項 作 用
-b filename 判斷檔案是否存在,并且是否為塊裝置檔案。
-c filename 判斷檔案是否存在,并且是否為字元裝置檔案。
-d filename 判斷檔案是否存在,并且是否為目錄檔案。
-e filename 判斷檔案是否存在。
-f filename 判斷檔案是否存在,井且是否為普通檔案。
-L filename 判斷檔案是否存在,并且是否為符号連結檔案。
-p filename 判斷檔案是否存在,并且是否為管道檔案。
-s filename 判斷檔案是否存在,并且是否為非空。
-S filename 判斷該檔案是否存在,并且是否為套接字檔案。
檔案權限判斷
選 項 作 用
-r filename 判斷檔案是否存在,并且是否擁有讀權限。
-w filename 判斷檔案是否存在,并且是否擁有寫權限。
-x filename 判斷檔案是否存在,并且是否擁有執行權限。
-u filename 判斷檔案是否存在,并且是否擁有 SUID 權限。
-g filename 判斷檔案是否存在,并且是否擁有 SGID 權限。
-k filename 判斷該檔案是否存在,并且是否擁有 SBIT 權限。
檔案比較
選 項 作 用
filename1 -nt filename2 判斷 filename1 的修改時間是否比 filename2 的新。
filename -ot filename2 判斷 filename1 的修改時間是否比 filename2 的舊。
filename1 -ef filename2 判斷 filename1 是否和 filename2 的 inode 号一緻,可以了解為兩個檔案是否為同一個檔案。這個判斷用于判斷硬連結是很好的方法

與數值比較相關的 test 選項

選 項 作 用
num1 -eq num2 判斷 num1 是否和 num2 相等。
num1 -ne num2 判斷 num1 是否和 num2 不相等。
num1 -gt num2 判斷 num1 是否大于 num2 。
num1 -lt num2 判斷 num1 是否小于 num2。
num1 -ge num2 判斷 num1 是否大于等于 num2。
num1 -le num2 判斷 num1 是否小于等于 num2。

與字元串判斷相關的 test 選項

選 項 作 用
-z str 判斷字元串 str 是否為空。
-n str 判斷宇符串 str 是否為非空。
str1 = str2 str1 == str2

=

==

是等價的,都用來判斷 str1 是否和 str2 相等。
str1 != str2 判斷 str1 是否和 str2 不相等。
str1 > str2 判斷 str1 是否大于 str2。

\>

>

的轉義字元,這樣寫是為了防止

>

被誤認為成重定向運算符。
str1 < str2 判斷 str1 是否小于 str2。同樣,

\<

也是轉義字元。

有C語言、C++、Python、Java 等程式設計經驗的讀者請注意,==、>、< 在大部分程式設計語言中都用來比較數字,而在 Shell 中,它們隻能用來比較字元串,不能比較數字,這是非常奇葩的,大家要習慣。

其次,不管是比較數字還是字元串,Shell 都不支援 >= 和 <= 運算符,切記

與邏輯運算相關的 test 選項

選 項 作 用
expression1 -a expression 邏輯與,表達式 expression1 和 expression2 都成立,最終的結果才是成立的。
expression1 -o expression2 邏輯或,表達式 expression1 和 expression2 有一個成立,最終的結果就成立。
!expression 邏輯非,對 expression 進行取反。

test 用變量建議用雙引号包起來

内置關鍵字

[[]]

幾乎完全相容 test ,并且比 test 更加強大,比 test 更加靈活的是

[[ ]]

[[ ]]

不是指令,而是 Shell 關鍵字

#用法
$ [[ expression ]]
           

[[ ]] 是 Shell 内置關鍵字,不是指令,在使用時沒有給函數傳遞參數的過程,是以 test 指令的某些注意事項在 [[ ]] 中就不存在了,具體包括:

  • 不需要把變量名用雙引号

    ""

    包圍起來,即使變量是空值,也不會出錯。
  • 不需要、也不能對 >、< 進行轉義,轉義後會出錯。

[[ ]] 支援邏輯運算符

注意,[[ ]] 剔除了 test 指令的

-o

-a

選項,你隻能使用 || 和 &&

[[ ]] 支援正規表達式

$ [[ str =~ regex ]]
           

但是 [[ ]] 對數字的比較仍然不友好,是以我建議,以後大家使用 if 判斷條件時,用 (()) 來處理整型數字,用 [[ ]] 來處理字元串或者檔案

關鍵字

case in

case expression in
    pattern1)
        statement1
        ;;
    pattern2)
        statement2
        ;;
    pattern3)
        statement3
        ;;
    ……
    *)
        statementn
esac
           

case、int 和 esac 都是 Shell 關鍵字,expression 表示表達式,pattern 表示比對模式。

  • expression 既可以是一個變量、一個數字、一個字元串,還可以是一個數學計算表達式,或者是指令的執行結果,隻要能夠得到 expression 的值就可以。
  • pattern 可以是一個數字、一個字元串,甚至是一個簡單的正規表達式。

case 會将 expression 的值與 pattern1、pattern2、pattern3 逐個進行比對:

  • 如果 expression 和某個模式(比如 pattern2)比對成功,就會執行這模式(比如 pattern2)後面對應的所有語句(該語句可以有一條,也可以有多條),直到遇見雙分号

    ;;

    才停止;然後整個 case 語句就執行完了,程式會跳出整個 case 語句,執行 esac 後面的其它語句。
  • 如果 expression 沒有比對到任何一個模式,那麼就執行

    *)

    後面的語句(

    *

    表示其它所有值),直到遇見雙分号

    ;;

    或者

    esac

    才結束。

    *)

    相當于多個 if 分支語句中最後的 else 部分

除最後一個分支外(這個分支可以是普通分支,也可以是

*)

分支),其它的每個分支都必須以

;;

結尾,

;;

代表一個分支的結束,不寫的話會有文法錯誤。最後一個分支可以寫

;;

,也可以不寫,因為無論如何,執行到 esac 都會結束整個 case in 語句

case in 的 pattern 部分支援簡單的正規表達式,具體來說,可以使用以下幾種格式

格式 說明
* 表示任意字元串。
[abc] 表示 a、b、c 三個字元中的任意一個。比如,[15ZH] 表示 1、5、Z、H 四個字元中的任意一個。
[m-n] 表示從 m 到 n 的任意一個字元。比如,[0-9] 表示任意一個數字,[0-9a-zA-Z] 表示字母或數字。
| 表示多重選擇,類似邏輯運算中的或運算。比如,abc | xyz 表示比對字元串 “abc” 或者 “xyz”。

while

while condition
do
    statements
done
           

until

until condition
do
    statements
done
#unti 循環和 while 循環恰好相反,當判斷條件不成立時才進行循環,一旦判斷條件成立,就終止循環
           

for

#c風格
for((exp1; exp2; exp3))
do
    statements
done
#python風格
for variable in value_list
do
    statements
done
           

對 value_list 的說明

  • 直接給出具體的值
    #!/bin/bash
    for str in "C語言中文網" "http://c.biancheng.net/" "成立7年了" "日IP數萬"
    do
        echo $str
    done
               
  • 給出一個取值範圍

    #{start..end}
    #demo
    #!/bin/bash
    sum=0
    for n in {1..100}
    do
        ((sum+=n))
    done
    echo $sum
               

    start 表示起始值,end 表示終止值;注意中間用兩個點号相連,而不是三個點号。根據筆者的實測,這種形式隻支援數字和字母

    再如,輸出從 A 到 z 之間的所有字元

    #!/bin/bash
    for c in {A..z}
    do
        printf "%c" $c
    done
    #結果為:ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz
    #可以發現,Shell 是根據 ASCII 碼表來輸出的
               
  • 使用指令的執行結果

    #!/bin/bash
    sum=0
    for n in $(seq 2 2 100)
    do
        ((sum+=n))
    done
    echo $sum
               
  • 使用 Shell 通配符

    #!/bin/bash
    for filename in *.sh
    do
        echo $filename
    done
               
  • 使用特殊變量

    #!/bin/bash
    function func(){
        for str in [email protected]
        do
            echo $str
        done
    }
    func C++ Java Python C#
    
    #其實,我們也可以省略 value_list,省略後的效果和使用[email protected]一樣
    #!/bin/bash
    function func(){
        for str
        do
            echo $str
        done
    }
    func C++ Java Python C#
               

select in

select variable in value_list
do
    statements
done
           

注意,select 是無限循環(死循環),輸入空值,或者輸入的值無效,都不會結束循環,隻有遇到 break 語句,或者按下 Ctrl+D 組合鍵才能結束循環

select in 通常和 case in 一起使用,在使用者輸入不同的編号時可以做出不同的反應

#!/bin/bash
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
do
    case $name in
        "Linux")
            echo "Linux是一個類UNIX作業系統,它開源免費,運作在各種伺服器裝置和嵌入式裝置。"
            break
            ;;
        "Windows")
            echo "Windows是微軟開發的個人電腦作業系統,它是閉源收費的。"
            break
            ;;
        "Mac OS")
            echo "Mac OS是蘋果公司基于UNIX開發的一款圖形界面作業系統,隻能運作與蘋果提供的硬體之上。"
            break
            ;;
        "UNIX")
            echo "UNIX是作業系統的開山鼻祖,現在已經逐漸退出曆史舞台,隻應用在特殊場合。"
            break
            ;;
        "Android")
            echo "Android是由Google開發的手機作業系統,目前已經占據了70%的市場佔有率。"
            break
            ;;
        *)
            echo "輸入錯誤,請重新輸入"
    esac
done
           
#運作結果示例
What is your favourite OS?
1) Linux
2) Windows
3) Mac OS
4) UNIX
5) Android
#? 7
輸入錯誤,請重新輸入
#? 4
UNIX是作業系統的開山鼻祖,現在已經逐漸退出曆史舞台,隻應用在特殊場合
           

break and continue

#可以跳出多層循環,不加n預設目前循環
break n
continue n
           

輸入輸出重定向

Linux 會給每個檔案配置設定一個 ID,這個 ID 就是一個整數,被稱為檔案描述符**(File Descriptor)**

檔案描述符 檔案名 類型 硬體
stdin 标準輸入 鍵盤
1 stdout 标準輸出 顯示器
2 stderr 标準錯誤輸出 顯示器

Linux 程式在執行任何形式的 I/O 操作時,都是在讀取或者寫入一個檔案描述符。一個檔案描述符隻是一個和打開的檔案相關聯的整數,它的背後可能是一個硬碟上的普通檔案、FIFO、管道、終端、鍵盤、顯示器,甚至是一個網絡連接配接。

stdin、stdout、stderr 預設都是打開的,在重定向的過程中,0、1、2 這三個檔案描述符可以直接使用

輸出重定向

輸出重定向是指指令的結果不再輸出到顯示器上,而是輸出到其它地方,一般是檔案中。這樣做的最大好處就是把指令的結果儲存起來,當我們需要的時候可以随時查詢。Bash 支援的重定向符号如下表所示

類 型 符 号 作 用
标準輸出重定向 指令 > 檔案 以覆寫的方式,把指令的正确輸出結果輸出到指定的檔案或裝置中。
标準輸出重定向 指令 >> 檔案 以追加的方式,把指令的正确輸出結果輸出到指定的檔案或裝置中。
标準錯誤輸出重定向 指令 2> 檔案 以覆寫的方式,把指令的錯誤資訊輸出到指定的檔案或裝置中。
标準錯誤輸出重定向 指令 2>> 檔案 以追加的方式,把指令的錯誤資訊輸出到指定的檔案或裝置中。
正确輸出和錯誤資訊同時儲存 指令 > 檔案 2> &1 以覆寫的方式,把正确輸出和錯誤資訊同時儲存到同一個檔案中。
同上 指令 >> 檔案 2> &1 以追加的方式,把正确輸出和錯誤資訊同時儲存到同一個檔案中。
同上 指令 &> 檔案 以覆寫的方式,把正确輸出和錯誤資訊同時儲存到同一個檔案中。
同上 指令 &>> 檔案 以追加的方式,把正确輸出和錯誤資訊同時儲存到同一個檔案中。
同上 指令 >> 檔案1 2>> 檔案2 把正确的輸出追加到檔案1中,把錯誤資訊追加到檔案2中。
  • /dev/null 檔案

    如果你既不想把指令的輸出結果儲存到檔案,也不想把指令的輸出結果顯示到螢幕上,幹擾指令的執行,那麼可以把指令的所有結果重定向到 /dev/null 檔案中。如下所示:

    ls -l &> /dev/null
               

輸入重定向

輸入重定向就是改變輸入的方向,不再使用鍵盤作為指令輸入的來源,而是使用檔案作為指令的輸入

符号 說明
指令 < 檔案 将指定的檔案作為指令的輸入。
指令 << 分界符 從标準輸入(鍵盤)中讀取資料,直到遇見分界符才停止。
指令 < 檔案1 > 檔案2 将檔案1作為指令的輸入,并将指令的處理結果輸出到檔案2。
  • 舉例 wc

    Linux wc 指令可以用來對文本進行統計,包括單詞個數、行數、位元組數,它的用法如下:

    wc  [選項]  [檔案名]
    #其中,-c選項統計位元組數,-w選項統計單詞數,-l選項統計行數
               
  • 統計使用者在終端輸入的文本的行數
    [c.biancheng.net]$ wc -l << END
    > 123
    > 789
    > abc
    > xyz
    > END
    4
    #wc 指令會一直等待用輸入,直到遇見分界符 END 才結束讀取
    #<<之後的分界符可以自由定義,隻要再碰到相同的分界符,兩個分界符之間的内容将作為指令的輸入(不包括分界符本身)
               

子產品化(内置指令source)

source 指令的用法為

$ source filename
#也可以簡寫為
$ . filename
           

source 是 Shell 内置指令的一種,它會讀取 filename 檔案中的代碼,并依次執行所有語句。你也可以了解為,source 指令會強制執行腳本檔案中的全部指令,而忽略腳本檔案的權限

#!/bin/bash
source func.sh
echo $(sum 10 20 55 15)
#source 後邊可以使用相對路徑,也可以使用絕對路徑,這裡我們使用的是相對路徑
           

避免重複引入

可以在子產品中額外設定一個變量,使用 if 語句來檢測這個變量是否存在,如果發現這個變量存在,就 return 出去

在 Shell 中,return 除了可以退出函數,還能退出由 source 指令引入的腳本檔案。

return 隻能退出由 source 指令引入的腳本檔案,對其它引入腳本的方式無效

if [ -n "$__MODULE_SH__" ]; then
    return
fi
__MODULE_SH__='module.sh'
echo "http://c.biancheng.net/shell/"
           
#!/bin/bash
source module.sh
source module.sh
echo "here executed"
           
運作 main.sh,輸出結果為:
http://c.biancheng.net/shell/
here executed
           

内建指令清單

Bash Shell 含有許多常用的指令,這些指令都已經内建在了 Shell 中。在使用這些指令時,執行速度就要快很多

相比外部指令,内建指令提供了更高的性能,但 Shell 中包含的内建指令越多,消耗的記憶體就會越大,而有些指令幾乎永遠也不會用到

指令 說明
: 擴充參數清單,執行重定向操作
. 讀取并執行指定檔案中的指令(在目前 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 還使用了許多環境變量。雖然環境變量不是指令,但它們通常會影響 Shell 指令的執行

可用 set 内建指令顯示這些環境變量。對于不同的 Linux 發行版,開機時設定的預設 shell 環境變量經常會不一樣

變量 說明
* 含有所有指令行參數(以單個文本值的形式)
@ 含有所有指令行參數(以多個文本值的形式)
# 指令行參數數目
? 最近使用的前台程序的退出狀态碼
- 目前指令行選項标記
$ 目前shell的程序 ID (PID)
! 最近執行的背景程序的 PID
指令行中使用的指令名稱
_ shell 的絕對路徑名
BASH 用來調用 shell 的完整檔案名
BASHOPTS 允許冒号分隔清單形式的 Shell 選項
BASHPID 目前 bash shell 的程序 ID
BASH_ALIASED 含有目前所用别名的數組
BASH_ARGC 目前子函數中的參數數量
BASH_ARGV 含有所有指定指令行參數的數組
BASH_CMDS 含有指令的内部散清單的數組
BASH_COMMAND 目前正在被執行的指令名
BASH_ENV 如果設定了的話,每個 bash 腳本都會嘗試在運作前執行由該變量定義的起始檔案
BASH_EXECUTION_STRING 在 -c 指令行選項中用到的指令
BASH_LINENO 含有腳本中每個指令的行号的數組
BASH_REMATCH 含有與指定的正規表達式比對的文本元素的數組
BASH_SOURCE 含有 shell 中已聲明函數所在源檔案名的數組
BASH_SUBSHELL 目前 shell 生成的子 shell 數目
BASH_VERS INFO 含有目前 bash shell 執行個體的主版本号和次版本号的數組
BASH_VERS ION 目前 bash shell 執行個體的版本号
BASH_XTRACEFD 當設定一個有效的檔案描述符整數時,跟蹤輸出生成,并與診斷和錯誤資訊分離開檔案描述符必須設定 -x 啟動
COLUMNS 含有目前 bash shell 執行個體使用的終端的寬度
COMP_CWORD 含有變量 COMP_WORDS 的索引直,COMP_WORDS 包含目前光标所在的位置
COMP_KEY 調用補全功能的按鍵
COMP_LINE 目前指令行
COMP_POINT 目前光标位置相對幹目前指令起始位置的索引
COMP_TYPE 補全類型所對應的整數值
COMP_WORDBREAKS 在進行單詞補全時闬作單詞分隔符的一組字元
COMP_WORDS 含有目前指令行上所有單詞的數組
COMPREPLY 含有由 shell 函數生成的可能補全碼的數組
COPROC 含有若幹匿名協程 I/O 的檔案描述符的數組
DIRSTACK 含有目錄棧目前内容的數組
EMACS 如果設定了該環境變量,則 shell 認為其使用的是 emacs shell 緩沖區,同時禁止行編輯功能
ENV 當 shell 以 POSIX 模式調用時,每個 bash 腳本在運作之前都會執行由該環境變量所定義的起始檔案
EUID 目前使用者的有效使用者 ID(數字形式)
FCEDIT fc 指令使用的預設編輯器
FIGNORE 以冒号分隔的字尾名清單,在檔案名補全時會被忽略
FUNCNAME 目前執行的 shell 函數的名稱
FUNCNEST 嵌套函數的最髙層級
GLOBIGNORE 以冒号分隔的模式清單,定義了檔案名展開時要忽略的檔案名集合
GROUPS 含有目前使用者屬組的數組
histchars 控制曆史記錄展開的字元(最多可有3個)
HISTCMD 目前指令在曆史記錄中的編号
HISTCONTROL 控制哪些指令留在曆史記錄清單中
HISTFILE 儲存 shell 曆史記錄清單的檔案名(預設是 .bash_history)
HISTFILESIZE 儲存在曆史檔案中的最大行數
HISTIGNORE 以冒号分隔的模式清單,用來決定哪些指令不存進曆史檔案
HISTSIZE 最多在曆史檔案中儲存多少條指令
HISTIMEFORMAT 設定後,決定曆史檔案條目的時間戳的格式字元串
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-公司-系統”格式定義的系統類型
MAILCHECK Shell 多久檢視一次新郵件(以秒為機關,預設值是 60)
MAPFILE 含有 mapfile 指令所讀入文本的數組,當沒有給出變量名的時候,使用該環境變量
OLDPWD shell 之前的工作目錄
OPTERR 設定為 1 時,bash shell 會顯示 getopts 指令産生的錯誤
OSTYPE 定義了 shell 運作的作業系統
PIPESTATUS 含有前台程序退出狀态碼的數組
POSIXLY_CORRECT 如果設定了該環境變量,bash 會以 POSIX 模式啟動
PPID bash shell 父程序的 PID
PROMPT_COMMAND 如果設定該環境變量,在顯示指令行主提示符之前會執行這條指令
PS1 主指令行提示符字元串
PS2 次指令行提示符字元串
PS3 select 指令的提示符
PS4 如果使用了 bash 的 -x 選項,在指令行顯示之前顯示的提示符
PWD 目前工作目錄
RANDOM 傳回一個 0~32 767 的随機數,對其指派可作為随機數生成器的種子
READLINE_LINE 儲存了 readline 行緩沖區中的内容
READLINE_POINT 目前 readline 行緩沖區的插入點位置
REPLY read 指令的預設變量
SECONDS 自 shell 啟動到現在的秒數,對其指派将會重置計時器
SHELL shell 的全路徑名
SHELLOPTS 已啟用 bash shell 選項清單,由冒号分隔
SHLVL 表明 shell 層級,每次啟動一個新的 bash shell 時計數加 1
TIMEFORMAT 指定了 shell 顯示的時間值的格式
TMOUT select 和 read 指令在沒輸入的情況下等待多久(以秒為機關)。預設值為零,表示無限長
TMPDIR 如果設定成目錄名,shell 會将其作為臨時檔案目錄
UID 目前使用者的真實使用者 ID (數字形式)

繼續閱讀