SHELL的種類
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
SHELL的程序結(jié)構(gòu)
#!/bin/bash
# 單行注釋用#號
:<<'多行注釋,<<后面也可以使用其他符號,前后要匹配一致
注釋內(nèi)容...
注釋內(nèi)容...
注釋內(nèi)容...
'
echo "Hello World !"
echo "執(zhí)行的文件名:$0"; # 執(zhí)行的文件名(包含文件路徑)
echo "第一個參數(shù)為:$1"; # 第一個參數(shù) 1
echo "第二個參數(shù)為:$2"; # 第二個參數(shù) 2
echo "第三個參數(shù)為:$3"; # 第三個參數(shù) 3
# 另外,還有幾個特殊字符用來處理參數(shù):
$# # 傳遞到腳本的參數(shù)個數(shù)
$* # 以一個單字符串顯示所有向腳本傳遞的參數(shù)。等價于 "1 2 3"
$@ # 與$*相同,但是使用時加引號,并在引號中返回每個參數(shù)。等價于 "1" "2" "3"
$$ # 腳本運行的當前進程ID號
$! # 后臺運行的最后一個進程的ID號
$- # 顯示Shell使用的當前選項,與[set命令]功能相同。
$? # 顯示最后命令的退出狀態(tài)。0表示沒有錯誤,其他任何值表明有錯誤。
$0 返回執(zhí)行shell名稱 # basename命令可以返回不包含路徑的腳本名
#! 是一個約定的標記,它告訴系統(tǒng)這個腳本需要什么解釋器來執(zhí)行,即使用哪一種 Shell。
SHELL的運行方法
- 作為可執(zhí)行程序
chmod +x ./test.sh #使腳本具有執(zhí)行權(quán)限
./test.sh 1 2 3 #執(zhí)行腳本,向腳本傳遞三個參數(shù) 1 2 3
注意,一定要寫成 ./test.sh,而不是 test.sh,運行其它二進制的程序也一樣,直接寫 test.sh,linux 系統(tǒng)會去 PATH 里尋找有沒有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的當前目錄通常不在 PATH 里,所以寫成 test.sh 是會找不到命令的,要用 ./test.sh 告訴系統(tǒng)說,就在當前目錄找。
- 作為解釋器參數(shù)
/bin/sh test.sh # 這種方式運行的腳本,不需要在第一行指定解釋器信息,寫了也沒用。
bash test.sh
sh test.sh
# 推薦下面的去執(zhí)行
source test.sh # 沒有權(quán)限的腳本不能直接被執(zhí)行,但是可以通過source或者.空格來執(zhí)行
. test.sh # .+空格+shell文件名
3.查看執(zhí)行結(jié)果碼
echo $?
正常 : 0
異常 : 0以外的正整數(shù),如1:無效的參數(shù),126:沒有權(quán)限執(zhí)行,127:無效的命令
exit 常量或變量 # 自定義程序返回碼,0~255
變量
定義變量時,變量名不加美元符號($,PHP語言中變量需要),如:
# 自定義變量
say_hi=hello,world # 不加引號時,值里有變量的會被解析后再輸出
say_hi='hello,world' # 單引號時,不轉(zhuǎn)義不解析變量
say_hi="hello,world" # 雙引號時,值里有變量的會被解析后再輸出,有命令要反引號一下(``)
# 自定義環(huán)境變量 /etc/profile-> ~/.bash_profile->~/.bashrc->/etc/bashrc
export 變量名=value # 1.變量名=value 2. export 變量名 的合并寫法
declare -x 變量名=value
# 環(huán)境變量,一般是指用export內(nèi)置命令導出的變量
export TOMCAT=/home/tom
# 有3個命令可以顯示變量的值
:<<'
set命令輸出所有的變量,包括全局變量和局部變量;set -o命令顯示bash Shell的所有參數(shù)配置信息。
env命令只顯示全局變量;
declare命令輸出所有的變量、函數(shù)、整數(shù)和已經(jīng)導出的變量。
'
使用一個定義過的變量,只要在變量名前面加美元符號即可,如:
say_hi="hello,world"
echo $say_hi
echo ${say_hi}
# 加花括號是為了幫助解釋器識別變量的邊界,比如下面這種情況:
for skill in Ada Coffe Action Java; do
# 如果不給skill變量加花括號,寫成echo "I am good at $skillScript",解釋器就會把$skillScript當成一個變量(其值為空)
echo "I am good at ${skill}Script"
done
# 只讀變量,使用 readonly 命令可以將變量定義為只讀變量,只讀變量的值不能被改變。
myUrl="https://www.google.com"
readonly myUrl
# 刪除變量, 變量被刪除后不能再次使用。
unset myUrl # unset 命令不能刪除只讀變量。
# 引號拼接字符串
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
# 獲取字符串長度
string="abcd"
echo ${#string} # 輸出 4,變量為數(shù)組時,${#string} 等價于 ${#string[0]}:
# 切片,提取子字符串
string="runoob is a great site"
echo ${string:1:4} # 輸出 unoo,注意:第一個字符的索引值為 0。
# 查找子字符串
string="runoob is a great site"
echo `expr index "$string" io` # 輸出 4,查找字符 i 或 o 的位置(哪個字母先出現(xiàn)就計算哪個):
# 定義數(shù)組
array_name=(value0 value1 value2 value3) # 數(shù)組名=(值1 值2 ... 值n)
array_name[0]=value0
# 讀取數(shù)組
valuen=${array_name[n]} # ${數(shù)組名[下標]}
echo ${array_name[@]} # 使用 @ 符號可以獲取數(shù)組中的所有元素
length=${#array_name[*]} # 或者*獲取數(shù)組中的所有元素(個數(shù))
運算符
原生bash不支持簡單的數(shù)學運算,但是可以通過其他命令來實現(xiàn),例如 awk 和 expr,expr 最常用。
- 算術運算符
#!/bin/bash
a = 10
b = 20
# 通過方括號實現(xiàn)計算
$[ operation ]
echo $[a * b] # 結(jié)果為 200。
# 通過expr命令實現(xiàn)計算
echo `expr $a + $b` # 結(jié)果為 30。
echo `expr $a \* $b` # 結(jié)果為 200。
echo `expr $b / $a` # 結(jié)果為 2。
echo `expr $b % $a` # 結(jié)果為 0。
# 通過bash bc計算器實現(xiàn)計算
c = $(bc << EOF # -q選項可以不顯示歡迎信息,通過print打印計算結(jié)果
scala=4 # 定義4位小數(shù)
a=10
b=20
a * b
EOF
)
echo c
echo a=$b # 賦值,把變量 b 的值賦給 a。
echo [ $a == $b ] # 比較兩個數(shù)字,返回 false。
echo [ $a != $b ] # 不相等,返回 true。
- 關系運算符
#!/bin/bash
a = 10
b = 20
echo [ $a -eq $b ] # 檢測兩個數(shù)是否相等,返回 false。
echo [ $a -ne $b ] # 不相等,返回 true。
echo [ $a -gt $b ] # 大于,返回 false。
echo [ $a -lt $b ] # 小于,返回 true。
echo [ $a -ge $b ] # 大于等于,返回 false。
echo [ $a -le $b ] # 小于等于,返回 true。
- 布爾運算符
#!/bin/bash
a = 10
b = 20
echo [ ! false ] # 非運算,返回 true。
echo [ $a -lt 20 -o $b -gt 100 ] # 或運算,返回 true。
echo [ $a -lt 20 -a $b -gt 100 ] # 與運算,返回 false。
echo [[ $a -lt 100 && $b -gt 100 ]] # 邏輯的 AND,返回 false
echo [[ $a -lt 100 || $b -gt 100 ]] # 邏輯的OR返回 true
- 字符串運算符
#!/bin/bash
a = "abc"
b = "efg"
echo [ $a = $b ] # 檢測兩個字符串是否相等,返回 false。
echo [ $a != $b ] # 是否不相等,返回 true。
echo [ -z $a ] # 字符串長度是否為0,返回 false。
echo [ -n "$a" ] # 字符串長度是否不為 0,返回 true。
echo [ $a ] 返回 # 字符串是否不為空,true。
- 文件測試運算符
#!/bin/bash
echo [ -d $file ] # 檢測文件是否是目錄,如果是,則返回 true。
echo[ -f $file ] # 是否是普通文件,返回 true。
echo [ -r $file ] # 是否可讀,返回 true。
echo [ -w $file ] # 是否可寫,返回 true。
echo [ -x $file ] # 是否可執(zhí)行,返回 true。
echo [ -s $file ] # 檢測文件是否為空(文件大小是否大于0),不為空返回 true。
echo [ -e $file ] # 檢測文件(包括目錄)是否存在,如果是,則返回 true。
命令
- echo
#!/bin/bash
# 顯示普通字符串:
echo "It is a test" # 這里的雙引號完全可以省略,以下命令與上面實例效果一致:
echo It is a test
# 顯示轉(zhuǎn)義字符
echo "\"It is a test\"" # "It is a test"
# 顯示變量
read name # 從標準輸入中讀取一行
echo "$name It is a test" # 把輸入行的每個字段的值指定給 shell 變量 + It is a test
# 顯示換行
echo -e "OK! \n" # -e 開啟轉(zhuǎn)義
# 顯示不換行
echo -e "OK! \c" # -e 開啟轉(zhuǎn)義 \c 不換行
# 顯示結(jié)果定向至文件
echo "It is a test" > myfile
# 原樣輸出字符串,不進行轉(zhuǎn)義或取變量(用單引號)
echo '$name\"' # $name\"
# 顯示命令執(zhí)行結(jié)果
echo `date` # Thu Jul 24 10:08:46 CST 2022
- printf
#!/bin/bash
echo "Hello, Shell" # Hello, Shell
printf "Hello, Shell\n" # echo同樣的結(jié)果,手動添加 \n
# 格式替代符 %s %c %d %f類型,%-10s指一個寬度為 10 個字符(- 表示左對齊,沒有則表示右對齊)
printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
- test
#!/bin/bash
# 用于檢查某個條件是否成立,它可以進行數(shù)值、字符和文件三個方面的測試。
num1=100
num2=100
if test $[num1] -eq $[num2] # 兩個數(shù)相等!
then
echo '兩個數(shù)相等!'
else
echo '兩個數(shù)不相等!'
fi
cd /bin
if test -e ./notFile -o -e ./bash # 如果文件存在則為真 ,與( -a )、或( -o )、非( ! )
then
echo '至少有一個文件存在!'
else
echo '兩個文件都不存在'
fi
流程控制
- 分支
#!/bin/bash
# if后面接命令,返回碼為0則執(zhí)行then語句,否則else語句。通過test命令才可實現(xiàn)表達式的判定
# 單括號允許在if語句中使用子shell
# 雙括號命令允許在test比較過程中使用高級數(shù)學表達式
# 雙方括號命令提供了針對字符串比較的高級特性
# 單分支
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
# 多分支
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "沒有符合的條件"
fi
# case ... esac
echo '輸入 1 到 4 之間的數(shù)字:'
echo '你輸入的數(shù)字為:'
read aNum
case $aNum in
1) echo '你選擇了 1'
;;
2) echo '你選擇了 2'
;;
3) echo '你選擇了 3'
;;
4) echo '你選擇了 4'
;;
*) echo '你沒有輸入 1 到 4 之間的數(shù)字'
;;
esac
- 循環(huán)
#!/bin/bash
# for 循環(huán) for var in list
# 環(huán)境變量IFS=$'\n' or \t ,internal field separator,內(nèi)部字段分隔符
for var in item1 item2 ... itemN; do command1; command2… done;
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done > output.txt # 結(jié)果輸出到output.txt而非屏幕上
# while 循環(huán)
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
# until 循環(huán)
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
# break 跳出所有循環(huán)(終止執(zhí)行后面的所有循環(huán)), break n 跳出n層循環(huán)
# continue 不會跳出所有循環(huán),僅僅跳出當前循環(huán)。continue n 繼續(xù)執(zhí)行n級循環(huán)
函數(shù)
#!/bin/bash
funWithReturn(){
echo "這個函數(shù)會對輸入的兩個數(shù)字進行相加運算..."
echo "輸入第一個數(shù)字: "
read aNum
echo "輸入第二個數(shù)字: "
read anotherNum
echo "兩個數(shù)字分別為 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum)) # 如果不加,將以最后一條命令運行結(jié)果,作為返回值。 return后跟數(shù)值n(0-255)
}
funWithReturn # 調(diào)用函數(shù)時可以向其傳遞參數(shù)。在函數(shù)體內(nèi)部,通過 $n 的形式來獲取參數(shù)的值,無須括號
echo "輸入的兩個數(shù)字之和為 $? !" # 函數(shù)返回值在調(diào)用該函數(shù)后通過 $? 來獲得。
SHELL的IO交互
- /dev/null 文件
/dev/null 是一個特殊的文件,寫入到它的內(nèi)容都會被丟棄;如果嘗試從該文件讀取內(nèi)容,那么什么也讀不到。但是 /dev/null 文件非常有用,將命令的輸出重定向到它,會起到"禁止輸出"的效果。如果希望執(zhí)行某個命令,但又不希望在屏幕上顯示輸出結(jié)果,那么可以將輸出重定向到 /dev/null
# 如果希望屏蔽 stdout 和 stderr,可以這樣寫:
command > /dev/null 2>&1
- 輸出重定向
# 文件描述符 0 通常是標準輸入(STDIN),1 是標準輸出(STDOUT),2 是標準錯誤輸出(STDERR)
command > file1 # 輸出重定向會覆蓋文件內(nèi)容
command >> file1 # 如果不希望文件內(nèi)容被覆蓋,可以使用 >> 追加到文件末尾
- 輸入重定向
# 需要從鍵盤獲取輸入的命令會轉(zhuǎn)移到文件讀取內(nèi)容
command < file1
command << EOF # 直到輸入EOF才會停止接收
SUB調(diào)用
#!/bin/bash
# 封裝一些公用的代碼作為一個獨立的文件,然后【. 文件名】來調(diào)用,F(xiàn)ULLPATH
. filename # 注意點號(.)和文件名中間有一空格
source filename # 或者這樣調(diào)用其他文件
# 被調(diào)用的文件 filename 不需要可執(zhí)行權(quán)限。
Linux三劍客
- grep
在文件或標準輸入中搜索指定的字符串或正則表達式,并輸出包含該字符串或匹配該正則表達式的所有行
grep "error" logfile.txt
- sed
用于編輯文本流的流編輯器,可以對輸入的文本進行替換、刪除、插入和打印等操作(不會修改源文件)。
sed 's/old/new/g' file.txt # 將file.txt文件中所有 "old" 替換為 "new" g替換全部,w可寫入文件
-e 執(zhí)行多個命令# sed -e 's /old/new;s/my/you/ test.txt' 命令之間必須以分號(;)分隔
-f 指定從文件讀取sed命令 # sed -f command.sed file.txt
-n 命令執(zhí)行后不顯示屏幕信息,sed -n ’s/old/new/p’ ,加了p則表示屏幕顯示替換后文本信息
替代字符/
sed編輯器允許選擇其他字符作為替換命令的替代分隔符
sed 's!/bin/bash!/bin/csh' /etc/passwd # 感嘆號(!)被用作替換命令的分隔符
使用地址
sed '2s/dog/cat/' data.txt # 第二行的dog變cat
sed '2,3s/dog/cat/' data.txt # 2-3行區(qū)間的被替換
sed '^&s/dog/cat/' data.txt # 開頭到結(jié)尾的被替換
使用文本模式過濾
sed '/rich/s/bash/csh/' etc/passwd # 替換只應用于包含匹配模式的行,只修改用戶rich的默認shell
使用命令組
sed '2,{ # 可以用花括號將其組合在一起執(zhí)行
>s/old/new/
>s/cat/dog/
}' data.txt
單行next命令
sed '/Header/{n;d}' data.txt # 先查找Header的那一行,找到之后next命令會移動到文本的下一行
多行next命令,合并文本行
sed '/Frist/{N;s/\n/ /}' data.txt # 先查找First那行,使用N命令將下一行與該行合并,然后將換行符(\n)替換成空格
多行刪除
sed 'N;/System\nAdmin/D'data.txt
多行打印
sed 'N;/System\nAdmin/P'data.txt
刪除
sed 'd' data.txt # 刪除全部文本
sed '3d' data.txt # 刪除指定文本
sed '/number 1/d'data.txt # 匹配到number 1的行被刪除
插入
當使用插入命令時,文本會出現(xiàn)在數(shù)據(jù)流文本之前
插入(insert)(i)命令會在指定行前增加一行
echo "line 2" | sed 'i \line 1' # 結(jié)果是line 1 換行l(wèi)ine2
附加(append)(a)命令會在指定行后增加一行
echo "line 1" | sed 'a \line 2' # 結(jié)果是line 2 換行l(wèi)ine1
sed '$a \ # 末尾追加多行,末尾必須追加反斜線
> text1
> text2
' data.txt
修改
修改(change)(c)命令允許修改數(shù)據(jù)流中整行文本的內(nèi)容
sed '2c\ # 修改第二行
> line2
'data.txt
sed '/test 1/c\ # 把匹配到的test 1 替換成text 2
>text 2
>'data.txt
轉(zhuǎn)換
轉(zhuǎn)換(y)命令是唯一可以處理單個字符的sed編輯器命令
sed 'y/123/789/'data.txt # 把inchar的第一個字符替換成outchar的第一個字符
- awk
一種文本處理工具,可用于對文本進行格式化和轉(zhuǎn)換。它可以讀取文本文件、執(zhí)行數(shù)學運算、進行邏輯操作、創(chuàng)建變量和數(shù)組等,gawk:GNU版本,屬于編程語言級別
awk '{ sum += $1 } END { print sum }' numbers.txt # 計算文件中所有數(shù)字的總和,Ctrl+D等于EOF
awk '{print $1}' file.txt 從 file.txt 文件中提取第一列,即每行第一個字段,默認分隔符時空白
-F 指定分隔符,awk -F: '{print $1}' /etc/passwd ,F后面指定冒號分隔符
awk -F: -f command.awk /etc/passwd ,f跟sed一樣從文件讀取命令
;分號 使用多條命令時用分號拼接
$0 表示整個文本行
$1...n 表示第幾個字段,即第幾列
BEGIN 讀取數(shù)據(jù)前執(zhí)行BEGIN關鍵字之后指定的腳本
END 指定一段腳本,gawk會在處理完數(shù)據(jù)后執(zhí)行這段腳本
gawk 'BEGIN {print "The data3 FILE Contens:"}
>{print $}
>END {print "End of File}' data3.txt
gawk 'BEGIN {FS=","} {print $1,$2,$3}' data # 逗號,分割字段,并打印第1,2,3列
gawk 'BEGIN {FS=",";OFS="-"} {print $1,$2,$3}' data # 逗號分隔后用-連接第1,2,3列
正則表達式
在 Linux 系統(tǒng)中,正則表達式經(jīng)常被用來進行文件搜索、文本處理、日志分析等操作。例如,可以使用 grep 命令來搜索包含某個正則表達式的文件,使用 sed 命令來對文本進行替換或刪除等操作。
字符類 []:
匹配一組字符中的任意一個字符。例如,[abc] 匹配字符 a、b 或 c。
元字符 .:
匹配除了換行符之外的任意單個字符。例如,a.b 匹配 "aab"、"abb"、"acb" 等。
量詞 {}:
用來指定某個模式的匹配次數(shù)。例如,a{3} 匹配 "aaa",a{1,3} 匹配 "a"、"aa" 或 "aaa"。
字符轉(zhuǎn)義 \:
用于將具有特殊含義的字符轉(zhuǎn)義為字面值。例如,\. 匹配 "."。
分組 ():
用于將多個模式組合成一個整體,以便對整個組合進行量詞或轉(zhuǎn)義。例如,(abc)+ 匹配 "abc"、"abcabc" 等。
錨點 ^和$:
用于匹配文本的開頭和結(jié)尾。例如,^abc 匹配以 "abc" 開頭的字符串,xyz$ 匹配以 "xyz" 結(jié)尾的字符串。