常用的Shell
Shell 既是一種腳本編程語言,也是一個連接內核和用戶的軟件。
常見的 Shell 有 sh、bash、csh、tcsh、ash 等。
bash shell 是 Linux 的默認 shell,bash 由 GNU 組織開發,保持了對 sh shell 的兼容性,是各種 Linux 發行版默認配置的 shell。
bash 兼容 sh 意味着,針對 sh 編寫的 Shell 代碼可以不加修改地在 bash 中運行。
儘管如此,bash 和 sh 還是有一些不同之處:
- 一方面,bash 擴展了一些命令和參數;
- 另一方面,bash 並不完全和 sh 兼容,它們有些行爲並不一致,但在大多數企業運維的情況下區別不大,特殊場景可以使用 bash 代替 sh。
查看Shell
Shell是一個程序,一般放在/bin
或/user/bin
目錄下,Linux系統可用的Shell都可以使用下面命令查看
user@PxeCtrlSys:~$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
現在Linux基本都是用的bash Shell,查看Linux的默認shell
user@PxeCtrlSys:~$ echo $SHELL
/bin/bash
運行方法
- 作爲可執行程序
代碼保存test.sh
文本中
# 進入腳本所在目錄,讓腳本擁有可執行權限
chmod +x ./test.sh
# 執行方式
./test.sh
一定要寫成./test.sh
,而不是test.sh
,運行其它二進制的程序也一樣,直接寫 test.sh
,linux 系統會去 PATH 裏尋找有沒有叫 test.sh
的,而只有 /bin
, /sbin
, /usr/bin
,/usr/sbin
等在 PATH 裏,你的當前目錄通常不在 PATH 裏,所以寫成 test.sh
是會找不到命令的,要用 ./test.sh
告訴系統說,就在當前目錄找。
- 作爲解釋器參數
直接運行解釋器,其參數就是 shell 腳本的文件名
/bin/sh test.sh
# 或者
/bin/bash test.sh
Shell變量
在Bash Shell中,每一個變量的值都是字符串,無論給變量賦值時有沒使用引號,值都會以字符串的形式存儲,即使將整數或小數賦值給變量,他們也會被視爲字符串。
變量賦值
定義變量,三種定義方式,顯式賦值
name="test"
name='test'
name=test
注意,變量名和等號之間不能有空格,這可能和你熟悉的所有編程語言都不一樣。同時,變量名的命名須遵循如下規則:
- 命名只能使用英文字母,數字和下劃線,首個字符不能以數字開頭。
- 中間不能有空格,可以使用下劃線(_)。
- 不能使用標點符號。
- 不能使用bash裏的關鍵字(可用help命令查看保留關鍵字)。
如果變量值包含空白字符,就必須使用引號包圍起來,例如name="bom smith"
用語句給變量賦值
for file in `ls /etc`
或
for file in $(ls /etc)
將/etc
目錄下的文件名循環出來。
使用變量
name="test"
echo $name
# 或者加花括號,含義一樣,加花括號是爲了幫助解釋器識別變量的邊界
echo ${name}
例如和變量連接的字符
#!/bin/bash
for item in Python Java Shell Bat; do
echo "This is ${item}Script"
done
運行結果如下
This is PythonScript
This is JavaScript
This is ShellScript
This is BatScript
如果沒有花括號,那麼變量就是$itemScript
,其值爲空,結果就會錯誤。推薦加花括號{}
。
修改變量的值
已定義過的變量可以重新賦值
#!/bin/bash
name='test'
echo ${name} # test
name="new"
echo $name # new
變量賦值不能加$
符號,只有在使用鍵盤時才能加$
。
命令執行結果賦值給變量
支持將命令的執行結果賦值給變量使用,常見的兩種方式:
value=`command`
# 或
value=$(command)
# 默認輸出以空白符填充
echo $value
# 按照原格式輸出,例如有換行符的
echo "$value"
第一種是使用反引號包圍起來,第二種是使用$()
包圍起來(推薦使用第二種方式)。command
是執行命令。
user@PxeCtrlSys:~$ res=`who`
user@PxeCtrlSys:~$ echo $res
user pts/0 2019-03-11 09:04 (192.168.96.16) user pts/1 2019-03-11 09:04 (192.168.96.16)
user@PxeCtrlSys:~$ res=$(ls /)
user@PxeCtrlSys:~$ echo $res
bin boot dev etc home initrd.img lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var vmlinuz
執行結果賦值給變量,輸出不會自動添加換行符。
如果被替換的命令的輸出內容包括多行(也即有換行符),或者含有多個連續的空白符,那麼在輸出變量時應該將變量用雙引號包圍,否則系統會使用默認的空白符來填充,這會導致換行無效,以及連續的空白符被壓縮成一個。請看下面的代碼:
user@PxeCtrlSys:~$ res=`who`
# 不用引號包圍變量,輸出不會自動換行
user@PxeCtrlSys:~$ echo $res
user pts/0 2019-03-11 09:04 (192.168.96.16) user pts/1 2019-03-11 09:04 (192.168.96.16)
# 使用引號包圍變量,輸出按照原來的格式
user@PxeCtrlSys:~$ echo "$res"
user pts/0 2019-03-11 09:04 (192.168.96.16)
user pts/1 2019-03-11 09:04 (192.168.96.16)
爲了防止出現格式混亂的情況,建議在輸出變量時加上雙引號。
只讀變量
使用 readonly
命令可以將變量定義爲只讀變量,只讀變量的值不能被改變。
下面的例子嘗試更改只讀變量,結果報錯:
#!/bin/bash
name='test'
readonly name
name='new'
echo $name
運行結果
test
/tmp/280278210/main.sh: line 4: name: readonly variable
# 當改爲只讀後,再次賦值就會報錯
刪除變量
使用 unset
命令可以刪除變量
#!/bin/bash
name='test'
unset name
echo $name # 執行沒有輸出
變量刪除後不能再次使用。unset
命令不能刪除只讀變量。
變量類型,作用域
運行shell時,會同時存在三種變量:
- 全局變量 指變量在當前的整個 Shell 會話中都有效。每個 Shell 會話都有自己的作用域,彼此之間互不影響。在 Shell 中定義的變量,默認就是全局變量。
- 局部變量 在 Shell 函數中定義的變量默認也是全局變量,它和在函數外部定義變量擁有一樣的效果;要想變量的作用域僅限於函數內部,那麼可以在定義時加上
local
命令,此時該變量就成了局部變量。 - 環境變量 只在當前 Shell 會話中有效,如果使用export命令將它導出,那麼它就在所有的子 Shell 中也有效了。
Shell字符串
字符串最常用的數據類型,可以用單/雙引號,也可以不用引號。
單引號
str='this is a string'
單引號字符串的限制:
- 單引號裏面的任何字符都會原樣輸出,單引號字符串裏面的變量是無效的,也就是變量那一串就只是字符串;
- 單引號字符中不能出現單獨一個的單引號(對單引號使用轉義符後也不行),但能成對出現,相當於字符串拼接
s='abc\'0e'
,這個就會報錯,而s='abc\'0'e'
會輸出abc\0e
雙引號
- 雙引號中可以有變量,輸出時會先解析裏面的變量和命令
- 雙引號也可以出現轉義字符
#!/bin/bash
name='lr'
echo $name
s1="my name is $name"
echo $s1
s2="my name is "$name""
echo $s2
s3="my name is \"$name\""
echo $s3
# 運行結果
lr
my name is lr
my name is lr
my name is "lr"
單/雙引號使用場景
建議:
- 如果變量的值是數字,那麼不加引號
a=1
; - 如果要將字符串原樣輸出,就用反引號
str='單引號中原樣輸出${test}'
; - 沒有特別要求最好都是用雙引號(最常見)。
拼接字符串
字符串的拼接(也稱字符串連接或者字符串合併),在 Shell 中你不需要使用任何運算符,將兩個字符串並排放在一起就能實現拼接。
#!/bin/bash
name='lr'
s1="hello, $name" # 雙引號中可以直接使用變量
echo $s1
s2="hello, "$name"" # 相當於兩對雙引號拼接
echo $s2
s3='hello, $name' # 單引號中變量都當作普通字符串
echo $s3
s4='hello, "$name"'
echo $s4
s5='hello, '$name'' # 相當於兩對單引號和變量進行拼接
echo $s5
nick='xy'
s6=$nick$name # 中間不能有空格
s7="$nick $name" # 如果是雙引號包圍,就允許中間有空格
s8=$nick"..."$name # 中間可以出現其他字符串
s9="$nick...$name" # 中間也可以這樣寫
s10="暱稱${nick}...${name}名字"
echo $s6
echo $s7
echo $s8
echo $s9
echo $s10
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
hello, lr
hello, lr
hello, $name
hello, "$name"
hello, lr
xylr
xy lr
xy...lr
xy...lr
暱稱xy...lr名字
獲取字符串長度
使用${#變量名}
獲取長度
#!/bin/bash
name='lr'
echo ${#name}
# 運行結果
2
截取字符串
Shell 截取字符串通常有兩種方式:從指定位置開始截取和從指定字符(子字符串)開始截取。
從指定位置開始截取
種方式需要兩個參數:除了指定起始位置,還需要截取長度,才能最終確定要截取的字符串。
從字符串左邊開始計數,格式爲${string: start :length}
#!/bin/bash
str="I love Python, but I need study Shell"
echo ${str:2:7} # 下標以0開始,從第2個開始截取,共截取7個字符
echo ${str:19} # 省略長度,直接從指定位置截取到最後
# 運行結果
love Py
I need study Shell
從右邊開始計數,格式爲${string: 0-start :length}
多了0-
,這是固定的寫法,專門用來表示從字符串右邊開始計數。
- 從左邊開始計數時,起始數字是 0(這符合程序員思維);從右邊開始計數時,起始數字是 1(這符合常人思維)。計數方向不同,起始數字也不同。
- 不管從哪邊開始計數,截取方向都是從左到右。
echo ${str:0-5:2} # 從右向左數第5個,長度爲2的字符串
echo ${str:0-5} # 省略長度,直接從指定位置截取到最後
# 運行結果
Sh
Shell
從指定字符(子字符串)開始截取
這種截取方式無法指定字符串長度,只能從指定字符(子字符串)截取到字符串末尾。Shell 可以截取指定字符(子字符串)右邊的所有字符,也可以截取左邊的所有字符。
使用 # 號截取右邊字符,格式爲${string#*chars}
其中,string
表示要截取的字符,chars
是指定的字符(或者子字符串),*
是通配符的一種,表示任意長度的字符串。*chars
連起來使用的意思是:忽略左邊的所有字符,直到遇見 chars
(chars
不會被截取)。
#!/bin/bash
str="I love Python, but I need study Shell"
echo ${str#*,} # 以 , 分割,取右邊
echo ${str#*Python,} # 以Python , 分割取右邊
echo ${str#I love} # 如果不需要忽略左邊的字符,那麼也可以不寫*
echo ${str#*o} # 以o分割,因爲字符串有好兩個o,那麼遇到第一個就結束了
echo ${str##*o} # 使用兩個#,就可以匹配到最後一個指定字符(子字符串)右方內容
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
but I need study Shell
but I need study Shell
Python, but I need study Shell
ve Python, but I need study Shell
n, but I need study Shell
如果希望直到最後一個指定字符(子字符串)再匹配結束,那麼可以使用##,具體格式爲:${string##*chars}
使用 % 截取左邊字符,格式爲${string%chars*}
#!/bin/bash
str="I love Python, but I need study Shell"
echo ${str%,*} # 以,分割,取左邊
echo ${str%Python,*} # 以Python,分割取左邊
echo ${str%Shell} # 如果不需要忽略右邊的字符,那麼也可以不寫*
echo ${str%o*} # 以o分割,因爲字符串有好兩個o,從右往左,那麼遇到第一個就結束了
echo ${str%%o*} # 使用兩個%%,就可以匹配到從右往左的最後一個指定字符(子字符串)左方內容
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
I love Python
I love
I love Python, but I need study
I love Pyth
I l
截取字符串彙總
格式 | 說明 |
---|---|
${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 左邊的所有字符。 |
查找字符串
#!/bin/bash
str="I love Python, but I need study Shell"
echo `expr index "$str" SP` # 查找字符S或者P最先出現的位置,下標以1開始,第8個字符爲P,就輸入了8
# 運行結果
8
以上腳本中 ` 是反引號,而不是單引號 '
Shell數組
bash支持一維數組(但不支持多維數組),並且沒有限制數組大小。數組元素的下標從0開始,獲取數組元素使用小標,下標可以試整數或算術表達式,其值應大於等於0。
定義數組
用括號表示數組,數組元素用空格
符號分隔開。
數組名=(值1 值2 值3 ... 值n)
或者
array_name=(
value0
value1
...
valuen
)
還可以單獨定義數組的各個分量
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
可以不使用連續的下標,而且下標的範圍沒有限制
array=([2]=12 [5]=99)
echo ${array[0]} # 爲空值
echo ${array[2]} # 輸出值爲12
array[0]=5 # 賦值一個
echo ${array[0]} # 輸出值爲5
# 獲取數組的所有元素
echo ${array[*]}
5 12 99
# 獲取數組長度
echo ${#array[*]}
3
讀取數組
一般格式
${數組名[下標]}
例如valuen=${array_name[n]}
,輸出數組所有元素用echo ${array_name[@]}
#!/bin/bash
arr[0]=1
arr[2]=2
echo ${arr[@]} # 使用 @ 符號可以獲取數組中的所有元素: 1 2
echo ${arr[2]} # 2
echo ${arr[1]} # 沒有的值獲取爲空
使用@
或*
可以獲取數組中的所有元素。
獲取數組的長度
所謂數組長度,就是數組元素的個數。
利用@
或*
,可以將數組擴展成列表,然後使用#
來獲取數組元素的個數,格式爲 ${#array_name[@]}
或 ${#array_name[*]}
,其中array_name
表示數組名。兩種形式是等價的。
#!/bin/bash
arr=(1 2 3 "abc")
echo ${#arr[@]} # 獲取數組的長度:4
echo ${#arr[*]} # *也可以:4
echo ${#arr[3]} # 獲取數組中單獨元素的長度:3
獲取數組中元素爲字符串的長度${#arr[2]}
(假設下標爲2的元素爲字符串),因爲獲取字符串長度的方法是 ${#string_name}
刪除數組的元素或數組
使用 unset arr[index]
刪除數組元素,使用 unset arr
刪除整個數組,所有元素都會消失。
#!/bin/bash
arr=(1 2 3 "abc")
echo ${#arr[@]} # 獲取數組的長度:4
echo 原來數組的長度爲:${#arr[*]} # *也可以:4
echo ${#arr[3]} # 獲取數組中單獨元素的長度:3
unset arr[1]
echo "刪除第二個元素後長度爲:${#arr[*]}"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
4
原來數組的長度爲:4
3
刪除第二個元素後長度爲:3
數組拼接、合併
將兩個數組連接成一個數組。
拼接數組的思路是:先利用@或*,將數組擴展成列表,然後再合併到一起。格式爲 array_new=(${array1[@]} ${array2[@]})
或 array_new=(${array1[*]} ${array2[*]})
#!/bin/bash
arr1=(1 2 3 "abc")
arr2=(66)
echo "數組1:${arr1[*]}"
echo "數組2:${arr2[@]}"
new_arr=(${arr1[*]} ${arr2[@]})
echo "合併後的數組爲:${new_arr[*]}"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
數組1:1 2 3 abc
數組2:66
合併後的數組爲:1 2 3 abc 66
Shell註釋
以#
開始的行就是註釋,會被解釋器忽略
通過每一行添加一個#
來設置多行註釋
如果在開發過程中,遇到大段的代碼需要臨時註釋起來,過一會兒又取消註釋,怎麼辦呢?
每一行加個#
符號太費力了,可以把這一段要註釋的代碼用一對花括號括起來,定義成一個函數,沒有地方調用這個函數,這塊代碼就不會執行,達到了和註釋一樣的效果。
多行註釋
:<<EOF
註釋內容...
註釋內容...
註釋內容...
EOF
EOF
也可以使用其他符號
:<<'
註釋內容...
註釋內容...
註釋內容...
'
:<<!
註釋內容...
註釋內容...
註釋內容...
!
Shell腳本傳遞參數
想腳本傳遞參數,腳本內獲取參數的格式爲:$n
。n
代表一個數字,1爲執行腳本的第一個參數,2爲執行腳本的第二個參數,以此類推...
給腳本文件傳遞參數
向腳本傳遞3個參數,其中$0
表示執行的文件名
user@PxeCtrlSys:~$ vim test.sh
user@PxeCtrlSys:~$ chmod +x test.sh # 添加執行權限
user@PxeCtrlSys:~$ ./test.sh
執行的文件名:./test.sh
傳遞的第一個參數:
傳遞的第二個參數:
傳遞的第三個參數:
所有參數:
user@PxeCtrlSys:~$ ./test.sh 1 2
執行的文件名:./test.sh
傳遞的第一個參數:1
傳遞的第二個參數:2
傳遞的第三個參數:
所有參數:1 2
user@PxeCtrlSys:~$ ./test.sh 1 2 3
執行的文件名:./test.sh
傳遞的第一個參數:1
傳遞的第二個參數:2
傳遞的第三個參數:3
所有參數:1 2 3
# test.sh文件內容
#!/bin/bash
echo "執行的文件名:$0"
echo "傳遞的第一個參數:$1"
echo "傳遞的第二個參數:$2"
echo "傳遞的第三個參數:$3"
echo "所有參數:$*"
如果參數個數太多,達到或者超過了 10 個,那麼就得用${n}
的形式來接收了,例如 ${10}
、${23}
。{ }
的作用是爲了幫助解釋器識別參數的邊界,這跟使用變量時加{ }
是一樣的效果。
特殊字符處理參數(特殊變量)
參數處理 | 說明 |
---|---|
$# |
獲取傳遞到腳本的參數個數 |
$* |
以一個單字符串顯示所有向腳本傳遞的參數,如$* 就和"$1 $2 $3 ... $n" 輸出形式一樣 |
$$ |
腳本運行的當前ID號 |
$! |
後臺運行的最後一個進程的ID號 |
$@ |
與$* 相同,但是使用時加括號,斌仔引號中返回每個參數,"$1" "$2" … "$n" 形式 |
$- |
顯示Shell使用的當前選項,與set命令功能相同 |
$? |
顯示最後命令的退出狀態。0表示沒有錯誤,其他任何值表示有錯誤 |
@ 的區別
- 相同點:都是引用所有參數
- 不同點:只有在雙引號中提現出來。假設在腳本運行時寫了三個參數1、2、3,則
*
等價於"1 2 3"
(傳遞了一個參數:會將所有的參數從整體上看做一份數據,而不是把每個參數都看做一份數據。),而@
等價於"1" "2" "3"
(仍然將每個參數都看作一份數據,彼此之間是獨立的)
#!/bin/bash
echo "執行的文件名:$0"
echo "傳遞的第一個參數:$1"
echo "傳遞的第二個參數:$2"
echo "傳遞的第三個參數:$3"
echo "\$*演示"
for i in "$*";do
echo $i
done
echo "\$@演示"
for j in $@;do
echo $j
done
# 運行結果
user@PxeCtrlSys:~$ ./test.sh 1 2 3
執行的文件名:./test.sh
傳遞的第一個參數:1
傳遞的第二個參數:2
傳遞的第三個參數:3
$*演示 # 只循環了一次,因爲$*當作一個參數
1 2 3
$@演示 # 循環多次,$@當作多個參數
1
2
3
Shell函數
shell函數格式
[ function ] funname [()]
{
action;
[return int;]
}
- 可以帶
function func()
定義,也可以直接func()
定義,不帶任何參數。 - 參數返回,可以顯示加:
return
返回,如果不加,將以最後一條命令運行結果,作爲返回值。return
後跟數值n(0-255)
無返回值函數
#!/bin/bash
func(){
echo "這是一個函數中的內容"
}
echo "開始調用函數"
func
echo "調用函數完成"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
開始調用函數
這是一個函數中的內容
調用函數完成
有返回值函數
定義一個帶return
的函數
#!/bin/bash
func(){
echo "請輸入兩個數,執行加法"
echo -n "請輸入第一個數:"
read num1
echo -n "請輸入第二個數:"
read num2
# return $[ $num1 + $num2]
# 下方表達式也正確
return $(( $num1 + $num2 ))
}
echo "開始調用函數"
func
echo "函數返回值爲 $?"
echo "調用函數完成"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
開始調用函數
請輸入兩個數,執行加法
請輸入第一個數:2
請輸入第二個數:3
函數返回值爲 5
調用函數完成
函數返回值在調用該函數後通過 $?
來獲得。
所有函數在使用前必須定義。這就是說必須將函數放在腳本開始部分,直到shell解釋器首次發現它時纔可以使用。調用函數僅使用其函數名即可。
$? 使用方法:返回值或退出狀態
$?
用來獲取函數返回值或者上一個命令的退出狀態
每一條 Shell 命令,不管是 Bash 內置命令(例如 test
、echo
),還是外部的 Linux 命令(例如 cd
、ls
),還是自定義的 Shell 函數,當它退出(運行結束)時,都會返回一個比較小的整數值給調用(使用)它的程序,這就是命令的退出狀態(exit status)。
if
語句的判斷條件,從本質上講,判斷的就是命令的退出狀態。
$? 獲取上一次命令退出狀態
退出狀態,就是上一個命令執行後的返回結果。退出狀態是一個數字,一般情況下,大部分命令執行成功會返回 0,失敗返回 1,這和C語言的 main() 函數是類似的。
不過,也有一些命令返回其他值,表示不同類型的錯誤。
#!/bin/bash
echo -n 請輸入a:
read a
echo -n 請輸入b:
read b
(( $a == $b ));
echo "退出狀態:$?"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
請輸入a:1
請輸入b:2
退出狀態:1
user@PxeCtrlSys:~$ echo $?
0
user@PxeCtrlSys:~$ ./test.sh
請輸入a:6
請輸入b:6
退出狀態:0
user@PxeCtrlSys:~$ echo $?
0
$? 獲取函數的返回值
給函數傳遞參數
Shell調用函數也可以向其傳遞參數。在函數體內部,通過 $n
的形式來傳遞參數。例如$1
表示第一個參數。$2
表示第二次參數
#!/bin/bash
func(){
echo "第一個參數:$1"
echo "第二個參數:$2"
echo "第二個參數:${2}"
echo "第五個參數:$5"
echo "第10個參數:$10" # 這個相當於第一個參數$1連接一個0
echo "第10個參數:${10}"
echo "第11個參數:$11" # 相當於第一個參數$1連接一個1
echo "第11個參數:${11}"
echo "參數總數有 $# 個"
echo "作爲一個地府傳輸出所有參數:$*"
}
echo "開始調用函數"
func 0 2 3 4 5 23 36 65 99 123
echo "函數返回值爲 $?"
echo "調用函數完成"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
開始調用函數
第一個參數:0
第二個參數:2
第二個參數:2
第五個參數:5
第10個參數:00
第10個參數:123
第11個參數:01
第11個參數:
參數總數有 10 個
作爲一個地府傳輸出所有參數:0 2 3 4 5 23 36 65 99 123
函數返回值爲 0
調用函數完成
$10
不能獲取到第10個參數,正確用法是${10}
。當n>=10
時,需要使用${n}
來獲取參數。
處理參數的特殊字符
參數處理 | 說明 |
---|---|
$# | 傳遞到腳本的參數個數 |
$* | 以一個單字符串顯示所有向腳本傳遞的參數 |
$$ | 腳本運行的當前進程ID號 |
$! | 後臺運行的最後一個進程的ID號 |
$@ | 與$*相同,但是使用時加引號,並在引號中返回每個參數。 |
$- | 顯示Shell使用的當前選項,與set命令功能相同。 |
$? | 顯示最後命令的退出狀態。0表示沒有錯誤,其他任何值表明有錯誤。 |
Shell基本運算符
支持的運算符
- 算術運算符
- 關係運算符
- 布爾運算符
- 字符串運算符
- 文件測試運算符
原生bash不支持簡單的數學運算,但可以使用其他命令實現,例如awk
、expr
(最常用)
expr
是一款表達式計算工具,使用它完成表達式的求值操作
例如,兩個數量價,注意是反引號,而不是單引號
#!/bin/bash
val=`expr 2+2`
echo "求值結果:$val"
val=`expr 2 + 2`
echo "求值結果:$val"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
求值結果:2+2
求值結果:4
- 表達式和運算符之間要用空格,例如
2+2
是不正確的,需要寫成2 + 2
,這與大多數編程語言不同 - 完整的表達式要被兩個反引號` `包含.
算術運算符
兩個數直接加不會進行算術運算
Shell 和其它編程語言不同,Shell 不能直接進行算數運算,必須使用數學計算命令。
默認情況下,Shell 不會直接進行算術運算,而是把+
兩邊的數據(數值或者變量)當做字符串,把+
當做字符串連接符,最終的結果是把兩個字符串拼接在一起形成一個新的字符串。這是因爲,在Shell如果不特別知名,每一個變量都是字符串,無論賦值的時候有沒使用引號,值都會以字符串形式存儲,默認情況下不區分變量類型。
Shell expr:進行整數計算
a 不等於 b
#!/bin/bash
a=2
b=3
echo `expr $a + $b`
echo `expr $a - $b`
echo `expr $a \* $b` # 做乘法需要添加斜槓轉義
echo `expr $b / $a`
echo `expr $b % $a`
c=$b
echo "賦值後c的值:$c"
if [ $a == $b ]
then
echo "a 等於 b"
else
echo "a 不等於 b"
fi
if [ $b == $c ]
then
echo "b 等於 c"
fi
if [ $a != $b ]
then
echo "a 不等於 b"
fi
if [ $c != $b ]
then
echo "c 不等於 b"
fi
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
5
-1
6
1
1
賦值後c的值:3
a 不等於 b
b 等於 c
a 不等於 b
運算符 | 說明 (例如a=2、b=3) | 舉例 |
---|---|---|
+ | 加法 | `expr b` 結果爲 30。 |
- | 減法 | `expr b` 結果爲 -10。 |
* | 乘法 | `expr b` 結果爲 200。 |
/ | 除法 | `expr a` 結果爲 2。 |
% | 取餘 | `expr a` 結果爲 0。 |
= | 賦值 | a=$b 將把變量 b 的值賦給 a。 |
== | 相等。用於比較兩個數字,相同則返回 true。 | [ b ] 返回 false。 |
!= | 不相等。用於比較兩個數字,不相同則返回 true。 | [ b ] 返回 true。 |
- 條件表達式要放在方括號之間,並且要有空格,例如:
[$a==$b]
是錯誤的,必須寫成[ $a == $b ]
。 - 乘號(
*
)前邊必須加反斜槓(\*
)才能實現乘法運算; if...then...fi
是條件語句- 在 MAC 中 shell 的
expr
語法是:$((表達式))
,此處表達式中的 "*" 不需要轉義符號 ""
數學計算命令
Shell 中常用的六種數學計算方式
運算操作符/運算命令 | 說明 |
---|---|
(()) |
用於整數運算,效率很高,推薦使用。 |
let |
用於整數運算,和 (()) 類似。 |
[$[] |
用於整數運算,不如 (()) 靈活。 |
expr |
可用於整數運算,也可以處理字符串。比較麻煩,需要注意各種細節,不推薦使用。 |
bc |
Linux下的一個計算器程序,可以處理整數和小數。Shell 本身只支持整數運算,想計算小數就得使用 bc 這個外部的計算器。 |
declare -i |
將變量定義爲整數,然後再進行數學運算時就不會被當做字符串了。功能有限,僅支持最基本的數學運算(加減乘除和取餘),不支持邏輯運算、自增自減等,所以在實際開發中很少使用。 |
Shell (()):對整數進行數學運算
(( ))
只能進行整數運算,不能對小數(浮點數)或者字符串進行運算。語法格式 ((表達式))
,就是將數學運算表達式放在((
和))
之間。
表達式可以只有一個,也可以有多個,多個表達式之間以逗號,
分隔。對於多個表達式的情況,以最後一個表達式的值作爲整個 (( ))
命令的執行結果。
可以使用$
獲取 (( ))
命令的結果,這和使用$
獲得變量值是類似的。
運算操作符/運算命令 | 說明 |
---|---|
((a=10+66) ((b=a-15)) ((c=a+b)) |
這種寫法可以在計算完成後給變量賦值。以 ((b=a-15)) 爲例,即將 a-15 的運算結果賦值給變量 c 。 注意,使用變量時不用加$ 前綴,(( )) 會自動解析變量名。 |
a=$((10+66) b=$((a-15)) c=$((a+b)) |
可以在 (( )) 前面加上$ 符號獲取 (( )) 命令的執行結果,也即獲取整個表達式的值。以 c=$((a+b)) 爲例,即將 a+b 這個表達式的運算結果賦值給變量 c 。 注意,類似 c=((a+b)) 這樣的寫法是錯誤的,不加$ 就不能取得表達式的結果。 |
((a>7 && b==c)) |
(( )) 也可以進行邏輯運算,在 if 語句中常會使用邏輯運算。 |
echo $((a+10)) |
需要立即輸出表達式的運算結果時,可以在 (( )) 前面加$ 符號。 |
((a=3+5, b=a+10)) |
對多個表達式同時進行計算。 |
在 (( ))
中使用變量無需加上$
前綴,(( ))
會自動解析變量名,這使得代碼更加簡潔,也符合程序員的書寫習慣。
算術運算
# 直接輸出運算結果
user@PxeCtrlSys:~$ echo $((1+1))
2
user@PxeCtrlSys:~$ echo $((2*3))
6
# 計算完成後,給變量賦值
user@PxeCtrlSys:~$ i=5
user@PxeCtrlSys:~$ ((i=i*2))
user@PxeCtrlSys:~$ echo $i
10
user@PxeCtrlSys:~$ ((i*=2)) # 簡寫,等效於 ((i=i*2))
user@PxeCtrlSys:~$ echo $i
20
# 複雜運算,結果賦值給變量a,變量在括號內
user@PxeCtrlSys:~$ ((a=2-5*2/4+2**2))
user@PxeCtrlSys:~$ echo $a
4
# 運算結果賦值給變量b,變量b在括號外,需要使用$
user@PxeCtrlSys:~$ b=$((2-5*2/4+2**2))
user@PxeCtrlSys:~$ echo $b
4
# 直接輸出表達式的值,$符號不能去掉
user@PxeCtrlSys:~$ echo $((2-5*2/4+2**2))
4
# 利用公式計算1-100的和
user@PxeCtrlSys:~$ echo $((100*(100+1)/2))
5050
邏輯運算
# 結果爲真,輸出1,1表示真
user@PxeCtrlSys:~$ echo $((3<5))
1
user@PxeCtrlSys:~$ echo $((3>5))
0
user@PxeCtrlSys:~$ echo $((3==2+1))
1
# 多條件成立
user@PxeCtrlSys:~$ if ((8>6&&5==2+3))
> then
> echo yes
> fi
yes
(())進行自增++和自減--運算
user@PxeCtrlSys:~$ a=10
# ++在後面,先輸出a的值,在自增
user@PxeCtrlSys:~$ echo $((a++))
10
user@PxeCtrlSys:~$ echo $a
11
# --在後面,先輸出a的值,再自減
user@PxeCtrlSys:~$ echo $((a--))
11
user@PxeCtrlSys:~$ echo $a
10
# --在前面,先自減,再輸出a的值
user@PxeCtrlSys:~$ echo $((--a))
9
user@PxeCtrlSys:~$ echo $a
9
# ++在前面,先自增,再輸出a的值
user@PxeCtrlSys:~$ echo $((++a))
10
user@PxeCtrlSys:~$ echo $a
10
多個表達式計算
# 先計算第一個表達式,再計算第二個表達式
user@PxeCtrlSys:~$ ((a=3*2, b=a+6))
user@PxeCtrlSys:~$ echo $a $b
6 12
# 以最後一個表達式的結果作爲整個(())命令的執行結果
user@PxeCtrlSys:~$ c=$((1+2, a+b))
user@PxeCtrlSys:~$ echo $c
18
Shell let:對整數進行數學運算
和雙小括號 (( ))
一樣,let
命令也只能進行整數運算,不能對小數(浮點數)或者字符串進行運算。
語法格式 let 表達式
、let "表達式"
、let '表達式'
,都等價於 ((表達式))
。
當表達式中含有 Shell 特殊字符(例如 |
)時,需要用雙引號" "
或者單引號' '
將表達式包圍起來。
和 (( ))
類似,let
命令也支持一次性計算多個表達式,並且以最後一個表達式的值作爲整個 let
命令的執行結果。但是,對於多個表達式之間的分隔符,let
和 (( ))
是有區別的:
let
命令以空格來分隔多個表達式;(( ))
以逗號,
來分隔多個表達式。
user@PxeCtrlSys:~$ i=2
user@PxeCtrlSys:~$ let i+=3
user@PxeCtrlSys:~$ echo $i
5
let i+=3
等價於((i+=3))
,但後者效率更高。
let
後面可以跟多個表達式,用空格分隔
user@PxeCtrlSys:~$ a=3
user@PxeCtrlSys:~$ let b=3**2 c=a+b
user@PxeCtrlSys:~$ echo $a $b
3 9
user@PxeCtrlSys:~$ echo $c
12
Shell $[]:對整數進行數學運算
和 (())
、let
命令類似,$[]
也只能進行整數運算。語法爲 $[表達式]
$[]
會對表達式
進行計算,並取得計算結果。如果表達式
中包含了變量,那麼你可以加$
,也可以不加。
# 直接輸出結果
user@PxeCtrlSys:~$ echo $[2*3]
6
user@PxeCtrlSys:~$ echo $[(2+3)/3]
1
user@PxeCtrlSys:~$ echo $[(2+3)%3]
2
user@PxeCtrlSys:~$ a=6
# 將結果賦值給變量
user@PxeCtrlSys:~$ b=$[a*2]
user@PxeCtrlSys:~$ echo $b
12
user@PxeCtrlSys:~$ echo $[a+b]
18
# 變量前加$對結果沒有影響
user@PxeCtrlSys:~$ echo $[$a+$b]
18
Shell declare -i:將變量聲明爲整數
默認情況下,Shell每一個變量的值都是一個字符串,即使給變量賦值一個數字,它也是字符串。
使用 declare
命令的-i
選項可以將一個變量聲明爲整數類型,這樣在進行數學計算時就不會作爲字符串處理了。
#!/bin/bash
echo 定義之前,直接求兩個數的和
m=2
n=3
echo $m+$n
echo 求和後賦值給一個變量
ret=$m+$n
echo $ret
echo -e "\n聲明變量爲整數"
declare -i m n ret
m=2
n=3
echo 直接輸出聲明後的求和
echo $m+$n
ret=$m+$n
echo 求和後賦值變量
echo $ret
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
定義之前,直接求兩個數的和
2+3
求和後賦值給一個變量
2+3
聲明變量爲整數
直接輸出聲明後的求和
2+3
求和後賦值變量
5
除了將 m
、n
定義爲整數,還必須將 ret
定義爲整數,如果不這樣做,在執行ret=$m+$n
時,Shell 依然會將 m
、n
視爲字符串。
此外,也不能寫類似echo $m+$n
這樣的語句,這種情況下 m
、n
也會被視爲字符串。
總之,除了將參與運算的變量定義爲整數,還得將承載結果的變量定義爲整數,而且只能用整數類型的變量來承載運算結果,不能直接使用 echo 輸出。
和 (())
、let
、$[]
不同,declare -i
的功能非常有限,僅支持最基本的數學運算(加減乘除和取餘),不支持邏輯運算(比較運算、與運算、或運算、非運算),所以在實際開發中很少使用。
關係運算符
關係運算符只支持數字,不支持字符串,除非字符串的值是數字
運算符 | 說明(例如a=2、b=3) | 舉例 |
---|---|---|
-eq | 等於檢測兩個數是否相等,相等返回 true。 | [ b ] 返回 false。 |
-ne | 不等於檢測兩個數是否不相等,不相等返回 true。 | [ b ] 返回 true。 |
-gt | 大於檢測左邊的數是否大於右邊的,如果是,則返回 true。 | [ b ] 返回 false。 |
-lt | 小於檢測左邊的數是否小於右邊的,如果是,則返回 true。 | [ b ] 返回 true。 |
-ge | 大等於檢測左邊的數是否大於等於右邊的,如果是,則返回 true。 | [ b ] 返回 false。 |
-le | 小等於檢測左邊的數是否小於等於右邊的,如果是,則返回 true。 | [ b ] 返回 true。 |
#!/bin/bash
a=2
b=3
if [ $a -eq $b ]
then
echo "a 大於 b"
else
echo "a 小於 b"
fi
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
a 小於 b
布爾運算符
運算符 | 說明(例如a=2、b=3) | 舉例 |
---|---|---|
! | 非運算,表達式爲 true 則返回 false,否則返回 true。 | [ ! false ] 返回 true。 |
-o | 或運算,有一個表達式爲 true 則返回 true。 | [ b -gt 100 ] 返回 true。 |
-a | 與運算,兩個表達式都爲 true 才返回 true。 | [ b -gt 100 ] 返回 false。 |
2 小於 5 或 3 大於 100 : 返回 true
#!/bin/bash
a=2
b=3
if [ $a != $b ]
then
echo "$a != $b : a 不等於 b"
else
echo "$a != $b: a 等於 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小於 100 且 $b 大於 15 : 返回 true"
else
echo "$a 小於 100 且 $b 大於 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a 小於 100 或 $b 大於 100 : 返回 true"
else
echo "$a 小於 100 或 $b 大於 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a 小於 5 或 $b 大於 100 : 返回 true"
else
echo "$a 小於 5 或 $b 大於 100 : 返回 false"
fi
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
2 != 3 : a 不等於 b
2 小於 100 且 3 大於 15 : 返回 false
2 小於 100 或 3 大於 100 : 返回 true
2 小於 5 或 3 大於 100 : 返回 true
邏輯運算符
運算符 | 說明 | 舉例 | ||||
---|---|---|---|---|---|---|
&& |
邏輯的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
||||
` | ` | 邏輯的OR | `[[ $a -lt 100 | $b -gt 100 ]]` 返回 true |
#!/bin/bash
a=2
b=3
if [[ $a -lt 5 && $b -gt 2 ]]
then
echo "返回true"
else
echo "返回false"
fi
if [[ $a -ge 2 || $b -le 3 ]]
then
echo "返回true"
else
echo "返回false"
fi
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
返回true
返回true
字符串運算符
運算符 | 說明 | 舉例 |
---|---|---|
= | 檢測兩個字符串是否相等,相等返回 true。 | [ b ] 返回 false。 |
!= | 檢測兩個字符串是否相等,不相等返回 true。 | [ b ] 返回 true。 |
-z | 檢測字符串長度是否爲0,爲0返回 true。 | [ -z $a ] 返回 false。 |
-n | 檢測字符串長度是否爲0,不爲0返回 true。 | [ -n "$a" ] 返回 true。 |
$ | 檢測字符串是否爲空,不爲空返回 true。 | [ $a ] 返回 true。 |
#!/bin/bash
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a 等於 b"
else
echo "$a = $b: a 不等於 b"
fi
if [ $a != $b ]
then
echo "$a != $b : a 不等於 b"
else
echo "$a != $b: a 等於 b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串長度爲 0"
else
echo "-z $a : 字符串長度不爲 0"
fi
if [ -n "$a" ]
then
echo "-n $a : 字符串長度不爲 0"
else
echo "-n $a : 字符串長度爲 0"
fi
if [ $a ]
then
echo "$a : 字符串不爲空"
else
echo "$a : 字符串爲空"
fi
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
abc = efg: a 不等於 b
abc != efg : a 不等於 b
-z abc : 字符串長度不爲 0
-n abc : 字符串長度不爲 0
abc : 字符串不爲空
文件測試運算符
文件測試運算符用於檢測Unix文件的各種屬性
操作符 | 說明 | 舉例 |
---|---|---|
-b file | 檢測文件是否是塊設備文件,如果是,則返回 true。 | [ -b $file ] 返回 false。 |
-c file | 檢測文件是否是字符設備文件,如果是,則返回 true。 | [ -c $file ] 返回 false。 |
-d file | 檢測文件是否是目錄,如果是,則返回 true。 | [ -d $file ] 返回 false。 |
-f file | 檢測文件是否是普通文件(既不是目錄,也不是設備文件),如果是,則返回 true。 | [ -f $file ] 返回 true。 |
-g file | 檢測文件是否設置了 SGID 位,如果是,則返回 true。 | [ -g $file ] 返回 false。 |
-k file | 檢測文件是否設置了粘着位(Sticky Bit),如果是,則返回 true。 | [ -k $file ] 返回 false。 |
-p file | 檢測文件是否是有名管道,如果是,則返回 true。 | [ -p $file ] 返回 false。 |
-u file | 檢測文件是否設置了 SUID 位,如果是,則返回 true。 | [ -u $file ] 返回 false。 |
-r file | 檢測文件是否可讀,如果是,則返回 true。 | [ -r $file ] 返回 true。 |
-w file | 檢測文件是否可寫,如果是,則返回 true。 | [ -w $file ] 返回 true。 |
-x file | 檢測文件是否可執行,如果是,則返回 true。 | [ -x $file ] 返回 true。 |
-s file | 檢測文件是否爲空(文件大小是否大於0),不爲空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 檢測文件(包括目錄)是否存在,如果是,則返回 true。 | [ -e $file ] 返回 true。 |
變量 file 表示文件"/home/user/test.sh",它的大小爲100字節,具有 rwx 權限。下面的代碼,將檢測該文件的各種屬性:
#!/bin/bash
file="/home/user/test.sh"
if [ -r $file ]
then
echo "文件可讀"
else
echo "文件不可讀"
fi
if [ -w $file ]
then
echo "文件可寫"
else
echo "文件不可寫"
fi
if [ -x $file ]
then
echo "文件可執行"
else
echo "文件不可執行"
fi
if [ -f $file ]
then
echo "文件爲普通文件"
else
echo "文件爲特殊文件"
fi
if [ -d $file ]
then
echo "文件是個目錄"
else
echo "文件不是個目錄"
fi
if [ -s $file ]
then
echo "文件不爲空"
else
echo "文件爲空"
fi
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
文件可讀
文件可寫
文件可執行
文件爲普通文件
文件不是個目錄
文件不爲空
文件存在
Shell內建(內置)命令
由 Bash 自身提供的命令,而不是文件系統中的某個可執行文件。
用於進入或者切換目錄的 cd 命令,雖然我們一直在使用它,但如果不加以注意很難意識到它與普通命令的性質是不一樣的:該命令並不是某個外部文件,只要在 Shell 中你就一定可以運行這個命令。
可以使用 type
來確定一個命令是否是內建命令:
user@PxeCtrlSys:~$ type cd
cd is a shell builtin # 內建命令
user@PxeCtrlSys:~$ type ls
ls is aliased to 'ls --color=auto'
user@PxeCtrlSys:~$ type ssh
ssh is /usr/bin/ssh # 外部命令
通常來說,內建命令會比外部命令執行得更快,執行外部命令時不但會觸發磁盤 I/O,還需要 fork 出一個單獨的進程來執行,執行完成後再退出。而執行內建命令相當於調用當前 Shell 進程的一個函數。
bash | : | . | [ | alias | bg | bind |
break | builtin | cd | command | compgen | complete | continue |
declare | dirs | disown | echo | enable | eval | exec |
exit | export | fc | fg | getopts | hash | help |
history | jobs | kill | let | local | logout | popd |
printf | pushd | pwd | read | readonly | return | set |
shift | shopt | source | suspend | test | times | trap |
type | typeset | ulimit | umask | unalias | unset | wait |
Shell alias:給命令創建別名
alias
用來給命令創建一個別名。
查看alias所有別名
若直接輸入該命令且不帶任何參數,則列出當前 Shell 環境中使用了哪些別名。
user@PxeCtrlSys:~$ alias
alias ls='ls --color=auto'
終於知道我的騰訊雲debian上ls
命令沒有顏色區分了
# 沒有爲ls創建別名
root@StarMeow-Svr:~# alias
root@StarMeow-Svr:~# alias ls='ls --color=auto'
root@StarMeow-Svr:~# ls
# 這兒的文件和文件夾就有顏色區分了
使用 alias
當然也可以自定義別名,比如說一般的關機命令是shutdown-h now
,寫起來比較長,這時可以重新定義一個關機命令,以後就方便多了。使用 alias 定義的別名命令也是支持 Tab 鍵補全的,如下所示:
alias myShutdown='shutdown -h now'
注意,這樣定義別名只能在當前 Shell 環境中有效,換句話說,重新登錄後這個別名就消失了。
永久生效alias別名
爲了確保永遠生效,可以將該別名手動寫入到用戶主目錄中的.bashrc
文件。
root@StarMeow-Svr:~# vim /root/.bashrc
# 將下方代碼取消被註釋
export LS_OPTIONS='--color=auto'
eval "`dircolors`"
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -l'
alias l='ls $LS_OPTIONS -lA'
# 修改完後使其生效
root@StarMeow-Svr:~# source ~/.bashrc
root@StarMeow-Svr:~# ls
# 這兒的文件和文件夾就有顏色區分了
root@StarMeow-Svr:~# alias
alias l='ls $LS_OPTIONS -lA'
alias ll='ls $LS_OPTIONS -l'
alias ls='ls $LS_OPTIONS'
刪除alias別名
使用 unalias
內建命令可以刪除當前 Shell 環境中的別名。unalias
有兩種使用方法:
- 第一種用法是在命令後跟上某個命令的別名,用於刪除指定的別名。
- 第二種用法是在命令後接
-a
參數,刪除當前 Shell 環境中所有的別名。
同樣,這兩種方法都是在當前 Shell 環境中生效的。要想永久刪除在.bashrc
文件中定義的別名,只能進入該文件手動刪除。
# 例如已經通過alias查到如下別名ls
user@PxeCtrlSys:~$ alias
alias ls='ls --color=auto'
# 使用unalias ls就可以刪除當前環境的別名
user@PxeCtrlSys:~$ unalias ls
Shell echo:輸出字符串
用於字符串輸出echo string
顯示普通字符串
echo "It is a string1"
這裏的雙引號可以完全省略
echo It is a string2
顯示轉義字符
#!/bin/bash
echo "\"It is a string1\""
echo \"It is a string2\"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
"It is a string1"
"It is a string2"
默認情況下,echo
不會解析以反斜槓\
開頭的轉義字符。比如,\n
表示換行,echo
默認會將它作爲普通字符對待。
echo "hello \nworld"
# 運行結果
hello \nworld
echo -e "hello \nworld"
# 運行結果
hello
world
同樣雙引號都是可以省略的
顯示變量
read
命令從標準輸入中讀取一行,並把輸入行的每個字段的值指定給shell變量
#!/bin/bash
read name
echo "You entered $name"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
66
You entered 66
顯示換行:-e參數和\n
#!/bin/bash
echo -e "this is first line \n"
echo "next"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
this is first line
next
輸出中-e
表示開啓轉義,\n
表示換行
顯示不換行:-e參數和\c或-n參數
#!/bin/bash
echo -e "this is first line \c"
echo "next"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
this is first line next
-e
開啓轉義,\c
表示不換行
echo -n "this is first line"
echo -n "next"
# 運行結果
this is first linenext
輸出結果重定向到文件
#!/bin/bash
echo -e "this is first line" > file.ts
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
user@PxeCtrlSys:~$ ls
file.ts software test.sh
user@PxeCtrlSys:~$ cat file.ts
this is first line
原樣輸出,不轉義,不取變量
直接使用單引號即可
#!/bin/bash
name='lr'
echo '$name"\'
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
$name"\
顯示命令執行結果
使用反引號,而不是單引號,可以執行Linux的命令
#!/bin/bash
echo `date`
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
Tue Mar 5 10:41:55 CST 2019
Shell exit:退出Shell命令
exit 是一個 Shell 內置命令,用來退出當前Shell:
- 如果在終端中直接運行
exit
命令,會退出當前登錄的 Shell,並關閉終端; - 如果在Shell中出現
exit
命令,會停止執行後邊的所有代碼,立即退出 Shell 腳本。
exit
命令可以接受的參數是一個狀態值 n
,代表退出時的狀態。如果不指定,默認狀態值是 0。
#!/bin/bash
echo "exit命令前輸出"
exit 9
echo "exit命令後輸出"
# 運行結果
user@PxeCtrlSys:~$ ./test.sh
exit命令前輸出 # 也就是說exit後面的語句已經不會執行了
# 緊接着用 $? 來獲取test.sh的退出狀態
user@PxeCtrlSys:~$ echo $?
9
Shell ulimit:顯示並設置進程資源速度
系統的可用資源是有限的,如果不限制用戶和進程對系統資源的使用,則很容易陷入資源耗盡的地步,而使用 ulimit 命令可以控制進程對可用資源的訪問(ulimit 是一個 Shell 內置命令)。
默認情況下 Linux 系統的各個資源都做了軟硬限制,其中硬限制的作用是控制軟限制(換言之,軟限制不能高於硬限制)。使用ulimit -a
可以查看當前系統的軟限制,使用命令ulimit -a –H
可查看系統的硬限制。
ulimit -a查看軟限制
user@PxeCtrlSys:~$ ulimit -a
core file size (blocks, -c) 0
# core文件大小,單位是block,默認爲0
data seg size (kbytes, -d) unlimited
# 數據段大小,單位是kbyte,默認不做限制
scheduling priority (-e) 0
# 調度優先級,默認爲0
file size (blocks, -f) unlimited
# 創建文件的大小,單位是block,默認不做限制
pending signals (-i) 15596
# 掛起的信號數量,默認是8192
max locked memory (kbytes, -l) 64
# 最大鎖定內存的值,單位是kbyte,默認是32
max memory size (kbytes, -m) unlimited
# 最大可用的常駐內存值,單位是kbyte,默認不做限制
open files (-n) 65536
# 最大打開的文件數,默認是1024
pipe size (512 bytes, -p) 8
# 管道最大緩衝區的值
POSIX message queues (bytes, -q) 819200
# 消息隊列的最大值,單位是byte
real-time priority (-r) 0
# 程序的實時性優先級,默認爲0
stack size (kbytes, -s) 8192
# 棧大小,單位是kbyte
cpu time (seconds, -t) unlimited
# 最大cpu佔用時間,默認不做限制
max user processes (-u) 15596
# 用戶最大進程數,默認是8192
virtual memory (kbytes, -v) unlimited
# 最大虛擬內存,單位是kbyte,默認不做限制
file locks (-x) unlimited
# 文件鎖,默認不做限制
每一行中都包含了相應的改變該項設置的參數,以最大可以打開的文件數爲例(open files
默認是 1024),想要增大至 4096 則按照如下命令設置(可參照此方法調整其他參數)。
# -n參數是設置最大文件打開數
# 下面命令會同時設置硬限制和軟限制
user@PxeCtrlSys:~$ ulimit -n 65536
# 使用-S參數單獨設置軟限制
user@PxeCtrlSys:~$ ulimit -S -n 65536
# 使用-H參數單獨設置硬限制
user@PxeCtrlSys:~$ ulimit -H -n 65536
limits.conf 配置文件
使用 ulimit
直接調整參數,只會在當前運行時生效,一旦系統重啓,所有調整過的參數就會變回系統默認值。所以建議將所有的改動放在 ulimit
的系統配置文件中。
user@PxeCtrlSys:~$ 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>
#
#Where:
#<domain>取值如下:一個用戶名、一個組名,組名前面用@符號、通配符*、通配符%
#<domain> can be:
# - a 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
# - NOTE: group and wildcard limits are not applied to root.
# To apply a limit to the root user, <domain> must be
# the literal username root.
#
#<type>有兩個可用值:soft用於設置軟限制、hard用於設置硬限制
#<type> can have the two values:
# - "soft" for enforcing the soft limits
# - "hard" for enforcing hard limits
#
#<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 (KB)
# - 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 values: [-20, 19]
# - rtprio - max realtime priority
# - chroot - change root to directory (Debian-specific)
#
#<domain> <type> <item> <value>
#
#以下是使用樣例
#* soft core 0
#root hard core 100000
#* hard rss 10000
#@student hard nproc 20
#@faculty soft nproc 20
#@faculty hard nproc 50
#ftp hard nproc 0
#ftp - chroot /ftp
#@student - maxlogins 4
# End of file