## shell入門教程
> Linux中的shell有多種類型,其中最常用的幾種是Bourne shell(sh)、C shell(csh)和Korn shell(ksh)。三種shell各有優缺點。
> Bourne shell是UNIX最初使用的shell,并且在每種UNIX上都可以使用。Bourne shell在shell編程方面相當優秀,但在處理與用戶的交互方面做得不如其他幾種shell。Linux操作系統缺省的shell是Bourne Again shell,它是Bourne shell的擴展,簡稱Bash,與Bourne shell完全向后兼容,并且在Bourne shell的基礎上增加、增強了很多特性。Bash放在/bin/bash中,它有許多特色,可以提供如命令補全、命令編輯和命令歷史表等功能,它還包含了很多C shell和Korn shell中的優點,有靈活和強大的編程接口,同時又有很友好的用戶界面。
可以使用 `cat /etc/shells` 查看支持的shell類型。我們最常用的就是bash。兼容sh
- 頭聲明
shell腳本第一行必須以 #!開頭,它表示該腳本使用后面的解釋器解釋執行。
```shell
#!/bin/bash
```
### shell變量
**shell變量中間不能有空格,合法的標識符(字母、數字、_),不能使用關鍵字。首字母必須是字母**
**變量賦值的時候,中間的等于號前后不能有空格**。
```shell
name=11
echo $name
1name //錯誤
_name //錯誤
name = "hello" //錯誤
```
2. 使用變量
定義過的變量直接使用$來訪問這個變量
```shell
name="test"
echo $name
echo ${name}
```
3. 只讀變量。
在一個變量的前面加上readonly 表示該變量只讀。類似于常量。
```
readonly PI=3.14
echo $PI
```
4. 刪除變量
當一個變量不再使用的時候,可以使用unset刪除
```shell
name="test"
unset $name
```
變量的類型。有局部變量、環境變量、shell變量
### 字符串
字符串和php類似。可以由雙引號和單引號括起來
但是雙引號括起來的字符串,里面的變量可以解析。
單引號里面不能出現雙引號(轉義也不可以).所以盡量使用雙引號
```shell
str="hello''"
str2='hello'
str3='"test"'//錯誤
str4="str2$str2"
echo $str4
```
- 字符串拼接
字符串拼接和其他的語言不一樣。不需要.也不需要+
```shell
name1="hello"
name2="world"
echo $name1 $name2// hello world
```
- 獲取字符串的長度
```shell
str="helloworld"
${#str}
```
- 字符串切片
使用冒號:
```
str="helloworld"
echo ${str:0:4} //從0開始截取4個字符 hell
```
- 字符串判斷操作
```shell
${var} 變量var的值, 與$var相同
${var-DEFAULT} 如果var沒有被聲明, 那么就以$DEFAULT作為其值 *
${var:-DEFAULT} 如果var沒有被聲明, 或者其值為空, 那么就以$DEFAULT作為其值 *
${var=DEFAULT} 如果var沒有被聲明, 那么就以$DEFAULT作為其值 *
${var:=DEFAULT} 如果var沒有被聲明, 或者其值為空, 那么就以$DEFAULT作為其值 *
${var+OTHER} 如果var聲明了, 那么其值就是$OTHER, 否則就為null字符串
${var:+OTHER} 如果var被設置了, 那么其值就是$OTHER, 否則就為null字符串
${var?ERR_MSG} 如果var沒被聲明, 那么就打印$ERR_MSG *
${var:?ERR_MSG} 如果var沒被設置, 那么就打印$ERR_MSG *
${!varprefix*} 匹配之前所有以varprefix開頭進行聲明的變量
${!varprefix@} 匹配之前所有以varprefix開頭進行聲明的變量
```
- 字符串截取
```shell
${#string} $string的長度
${string:position} 在$string中, 從位置$position開始提取子串
${string:position:length} 在$string中, 從位置$position開始提取長度為$length的子串
${string#substring} 從變量$string的開頭, 刪除最短匹配$substring的子串
${string##substring} 從變量$string的開頭, 刪除最長匹配$substring的子串
${string%substring} 從變量$string的結尾, 刪除最短匹配$substring的子串
${string%%substring} 從變量$string的結尾, 刪除最長匹配$substring的子串
${string/substring/replacement} 使用$replacement, 來代替第一個匹配的$substring
${string//substring/replacement} 使用$replacement, 代替所有匹配的$substring
${string/#substring/replacement} 如果$string的前綴匹配$substring, 那么就用$replacement來代替匹配到的$substring
${string/%substring/replacement} 如果$string的后綴匹配$substring, 那么就用$replacement來代替匹配到的$substring
例子
str="hello"
echo ${#str}//5
echo ${str:0:2} //he
echo ${str/l/test}//heltesto
echo ${str//l/test} //hetesttesto
```
### 數組
shell數組支持一維數組。和php類似。不需要指定數組的大小。
數組用括號抱起來。每個元素用空格分割
arr=(a1 a2 a3)
```shell
arr=(1 2 3)
${arr[0]}//1
```
- 獲取數組所有的元素
使用@ 或 * 可以獲取數組中的所有元素
```shell
${arr[*]}
```
- 獲取數組的長度
```shell
${#arr[*]}
```
- 遍歷數組
```shell
for a in ${arr[*]};do
echo $a
done
```
- 數組第n個元素的長度
```shell
${#arr[2]}
```
- 數組切片
```shell
${arr[*]:0:2} //1 2
```
- 數組搜索替換
```shell
${arr[*]/3/5}
```
- 添加元素到數組
```shell
arr=("${arr[*]}" "test")
```
## 運算符
### 邏輯運算符
```shell
&& 邏輯的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 邏輯的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true
```
### 字符串比較
```shell
= 檢測兩個字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 檢測兩個字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 檢測字符串長度是否為0,為0返回 true。 [ -z $a ] 返回 false。
-n 檢測字符串長度是否為0,不為0返回 true。 [ -n $a ] 返回 true。
str 檢測字符串是否為空,不為空返回 true。 [ $a ] 返回 true。
```
### 關系運算符
關系運算符只支持數字
```shell
eq 檢測兩個數是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
-ne 檢測兩個數是否相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 檢測左邊的數是否大于右邊的,如果是,則返回 true。 [ $a -gt $b ] 返回 false。
-lt 檢測左邊的數是否小于右邊的,如果是,則返回 true。 [ $a -lt $b ] 返回 true。
-ge 檢測左邊的數是否大于等于右邊的,如果是,則返回 true。 [ $a -ge $b ] 返回 false。
-le 檢測左邊的數是否小于等于右邊的,如果是,則返回 true。 [ $a -le $b ] 返回 true。
```
```shell
a=10
b=20
if [[ $a eq $b ]];then
echo "等于"
fi
```
### 布爾運算符
```shell
! 非運算,表達式為 true 則返回 false,否則返回 true。 [ ! false ] 返回 true。
-o 或運算,有一個表達式為 true 則返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a 與運算,兩個表達式都為 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。
```
### 文件測試符號
```shell
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。
```
```shell
file=""
if [[-f $file ]]; then
echo "is a file"
fi
```
## 流程控制
### if/else
```shell
if [[condition]];then
echo '1'
fi
//if else
if [[condition]]; then
echo '1'
else
echo '2'
fi
# if elseif else
if [[condition]];then
elif [[condition]];then
fi
```
### for
```shell
for i in list1 list2 ;do
echo $i
done
for i in 1 2 3 4;do
echo $i
done
//1 2 3 4
for (( i = 0; i < 10; i++ )); do
echo $i
done
```
### while
```shell
while [[ condition ]]; do
#statements
done
```
**demo例子**
```shell
#! /bin/bash
a=10
b=20
# 判斷數值
if [[ $a -ne $b ]]; then
echo "a 不等于b"
fi
# 判斷字符串
if [[ '$a' != '$b' ]]; then
echo "1"
fi
# 判斷文件
if [[ -d "../doc" ]]; then
echo "dirctory"
fi
if [[ ! -f "../routes" ]]; then
echo "not a file"
fi
#while
while [[ $a -gt 1 ]]; do
#statements
echo $a;
# 條件
let a--
done
# for
for i in "wo" "rds"; do
echo $i
done
```
## 函數
shell中的函數 定義如下
```shell
其中function是可以省略的
[function] functionName(){}
function test(){
}
test(){
}
```
- 函數的調用
函數的調用和其他語言的調用不太一樣
```shell
function test()
{
echo "hello"
}
test #調用函數
```
- 函數的參數
函數的參數定義不需要在()中定義形參 只需要在調用使用傳入即可
`$n n代表整數` $1是第一個參數 以此類推
```shell
function test()
{
echo $1 # 第一個參數 以此類推
}
test 22 //22
```
## 引入外部文件
在shell中有時候需要引入外部的腳本文件 我們需要使用下面的兩種方式
1. . filename
```shell
. ./a.sh
```
2. source filename
在文件中使用source
```shell
source ./a.sh
```
## 命令行接收參數
在執行 Shell 腳本時,向腳本傳遞參數,腳本內獲取參數的格式為:$n。n 代表一個數字,1 為執行腳本的第一個參數,2 為執行腳本的第二個參數。
```shell
$ bash test.sh test test2
$0 代表腳本文件 //test.sh
$1 代表第一個參數 //test
$# 參數的個數 // 2
$* 所有參數
for i in $*; do
echo $i
done
$$ 腳本運行的進程號
$! 最后一個進程號
$? 最后退出的狀態 0 表示沒有問題
```
- PC
- IO模型
- Inode介紹
- Linux
- Linux基本操作命令
- Linux網絡相關命令
- Crontab計劃任務
- Shell
- Sed命令
- Awk命令
- LAMP/LNMP
- PHP
- 基本語法
- 面向對象
- 錯誤和異常處理
- 命名空間
- PHP7
- 正則表達式
- Hashtable
- 變量的內部實現
- PHP-FPM
- PHP運行原理
- swoole
- mysql
- SQL標準
- mysql三范式
- 存儲引擎
- Mysql事務
- Mysql索引
- Mysql優化
- Explain
- MySQL索引原理及慢查詢優化
- MongoDb
- 計算機網絡
- IP協議
- TCP(傳輸控制協議)
- UDP(用戶數據報協議)
- HTTP 協議
- HTTPS
- HTTP的基本優化
- Websocket協議
- 版本控制器
- Git
- Svn
- 數據結構
- 數組
- 鏈表
- 算法