shell編程筆記1--shell基礎
shell編程筆記1–shell基礎
shell是linux使用者必須掌握的一項技能,筆者使用了多年的linux一直以來沒有來得及做一個簡單的學習文檔,最近抽空將常用的shell編程要點加以總結,以供後續查閱;後續也會在此基礎上持續更新,並補充重要知識點和功能函數。
筆記1–變量
- 變量定義與引用
字符串類型,不解析任何字符。
var1=‘var1’
雙引號內部會解析$和反斜槓特殊字符。
var2=“var2\var3”
反引號或$()執行系統命令
now_date=`date`
cur_dir=$(pwd)
使用變量直接加$即可,變量名外面的花括號是可選的,加花括號是爲了幫助解釋器識別變量的邊界
echo $var1 $var2 $now_date “current dir:${cur_dir}” - 變量類型
常見環境變量:
PATH:系統路徑;
HOME:當前用戶家目錄;
HISTSIZE:保存歷史命令記錄的條數;
LOGNAME:當前用戶登錄名;
HOATNAME:主機名稱,若應用程序要用到主機名的話,一般是從這個環境變量中的取得的;
SHELL:當前用戶用的是哪種shell;
LANG:和語言相關的環境變量,使用多種語言的用戶可以修改此環境變量;
env 可以查看所有環境變量 - 預定義變量
預定義變量爲shell內部使用的變量,與不能重定義,常見如下:
$@ 傳入的所有參數
$# 位置參數的數量
$* 所有位置參數的內容
$? 命令執行後返回的狀態, 0表示成功,非0表示失敗
$$ 當前進程的進程號
$! 後臺運行的最後一個進程號,很少用
$0 當前執行的進程名,即執行腳本
$1-n 傳入的1-n個參數測試: bash test.sh para1 para2 para3 $@ para1 para2 para3 $# 3 $* para1 para2 para3 $? 0 $$ 18687 $! $0 test.sh $1 para1
- declare和typeset
命令兩者等價,都是用來定義變量類型的,相關參數說明如下:
-r 將變量設爲只讀
-i 將變量設爲整數
-a 將變量定義爲數組
-f 顯示此腳本前定義過的所有函數及內容
-F 進顯示此腳本前定義過的函數名
-x 將變量聲明爲環境變量,env中可以查看到定義的環境變量
示例:$ num1=1 $ num2=$num1+1 $ echo $num2 1+1 $ declare -i num3 $ num3=$num1+10 $ echo $num3 11
- 註釋
單行註釋方法爲: # 註釋內容
多行註釋方法:方法1: if false; then echo '1' echo '2' fi 方法2: ((0))&&{ echo '1' echo '2' }
- 重定向
cmd > file #重定向到file
cmd >> file #追加的方式重定向到file
cmd > /dev/null #重定向到空設備文件
linux下輸入、輸出、錯誤描述符:
標準輸入文件(stdin):stdin的文件描述符爲0,Unix程序默認從stdin讀取數據;
標準輸出文件(stdout):stdout 的文件描述符爲1,Unix程序默認向stdout輸出數據;
標準錯誤文件(stderr):stderr的文件描述符爲2,Unix程序會向stderr流中寫入錯誤信息。
cmd > file 2>&1 # 將標準輸出和標準錯誤輸出重定向到file文件。
cmd > /dev/null 2>&1 # 屏蔽所有輸出 - 交互式輸入read
read可在shell中實現交互式輸入, -p可實現帶提示的交互式輸入,示例如下:function interact(){ echo 'input var1:' read var1 echo 'var1 is ' $var1 read -p 'input var2:' var2 echo 'var2 is ' $var2 } 執行結果: input var1: 001 var1 is 001 input var2 002 var2 is 002
筆記2–運算、比較操作
- 加減乘除三種表示方法
1-let命令:
let “sum=3+5”
echo $sum
2-expr命令:
sum=`expr 2 - 5` #注意-左右有空格
echo $sum
注意:使用乘法 * 的時候需要轉義\*否則會出錯。
3-使用(( … )) 的形式:
sum=$((3+5))
echo $sum
4-使用bc進行浮點運算
使用方法:variable=`echo “OPTIONS; OPERATIONS” | bc`
例如:n=`echo “scale=3; 13 / 2” | bc`
echo $n 結果爲6.500,其中scale=3表示小數點位數。 - 常見比較操作
- test整數比較方法
大於 -gt
小於 -lt
大於等於 -ge
小於等於 -le
等於 -eq
不等於 -ne示例: $ a=100 $ b=200 $ test $a -lt $b $ echo $? 0 $ test $a -eq $b $ echo $? 1
- test字符串比較
測試空字符串-z
測試字符串的長度爲非零-n
等於某一個字符串=不等於某一個字符串!= - test邏輯與非
-a 邏輯與
-o 邏輯非$ a=100 $ b=200 $ test $a -eq 100 -a $b -eq 200 $ echo $? 0 $ test $a -eq 101 -o $b -eq 200 $ echo $? 0 $ test $a -eq 101 -o $b -eq 201 $ echo $? 1
- 文件比較
文件類型說明:
常規文件 -
目錄文件 d
字符設備 c
塊設備 b
套接字 s
鏈接 l
test -f $filename #文件存在
test -d $filename #目錄存在
test -r $filename #文件是否可讀
test -w $filename #文件是否可寫
test -x $filename #文件是否可執行
筆記3–字符串 數組
3.1 字符串
- 字符串分割方法:
假設有變量 var=http://www.aaa.com/123.htm.- #號截取,刪除左邊字符,保留右邊字符。
echo ${var#//}
其中 var 是變量名,# 號是運算符,// 表示從左邊開始刪除第一個 // 號及左邊的所有字符
即刪除 http://
結果是 :www.aaa.com/123.htm - # 號截取,刪除左邊字符,保留右邊字符。
echo ${var##/}
##/ 表示從左邊開始刪除最後(最右邊)一個 / 號及左邊的所有字符
即刪除 http://www.aaa.com/
結果是 123.htm - %號截取,刪除右邊字符,保留左邊字符
echo ${var%/}
%/ 表示從右邊開始,刪除第一個 / 號及右邊的字符
結果是:http://www.aaa.com - %% 號截取,刪除右邊字符,保留左邊字符:
echo ${var%%/}
%%/ 表示從右邊開始,刪除最後(最左邊)一個 / 號及右邊的字符
結果是:http: - 從左邊第幾個字符開始,及字符的個數
複製代碼 代碼如下:
echo ${var:0:5}
其中的 0 表示左邊第一個字符開始,5 表示字符的總個數。
結果是:http: - 從左邊第幾個字符開始,一直到結束。
echo ${var:7}
其中的 7 表示左邊第8個字符開始,一直到結束。
結果是 :www.aaa.com/123.htm - 從右邊第幾個字符開始,及字符的個數
echo ${var:0-7:3}
其中的 0-7 表示右邊算起第七個字符開始,3 表示字符的個數。
結果是:123 - 從右邊第幾個字符開始,一直到結束。
echo ${var:0-7}
表示從右邊第七個字符開始,一直到結束。
結果是:123.htm
注:左邊的第一個字符是用 0 表示,右邊的第一個字符用 0-1 表示
- #號截取,刪除左邊字符,保留右邊字符。
- expr字符串操作
- 字符串長度
$ str1=“abcde12345”
$ echo ${#str1}
10
$ expr length $str1
10 - 取子字符串
取子串方法:
1)expr substr $string $position $length #注意位置編號從1開始
2)echo ${string:$pos:$length} # 注意位置編號從0開始
$ string=“abcde1234567890”
$ expr substr $string 1 3
abc
$ echo ${string:0:3}
abc
- 字符串長度
- 字符串連接
$ str1=abc
$ str2=def
$ str3=$str1$str2
$ echo $str3
abcdef
$ str3="${str1}-${str2}" # 通過{}可以自定義分隔符
$ echo $str3
abc-def - 字符串替換
$ string=“you and you and zhangsan”
$ echo ${string/you/YOU} # 只替換一次
YOU and you and zhangsan
$ echo ${string//you/YOU} # 全部替換
YOU and YOU and zhangsan
3.2 數組
數組常見操作如下:
1)定義一個數組: myarray=(1 2 3 4 5)
2)讀取數組的某一個元素 : echo ${myarray[下標值]} # 注意數組名稱必須使用{} 括起來, 下標值從0開始編號
3)數組元素的賦值: myarray[下標值] = xxx
4)顯示數組的所有元素: echo ${myarray[]}
5)獲得數組的長度: echo ${#array[@]} 或者 echo ${#array[]}
6)刪除一個數組元素: unset myarray[下標值]。
案例:for循環輸出數組
function printarray(){
arr=(0 1 2 3 4 5 6)
len=${#arr[@]}
for (( i=0; i<$len; i++ ))
do
echo ${arr[$i]}
done
}
注意:for循環中 (( 與 ))和其它變量之間有空格
筆記4–順序 選擇 循環結構
4.1 順序
shell默認採用順序結構執行各條命令
4.2 選擇
- if else選擇
if elif else是最簡單的選擇結構,具體示例如下:function testslect(){ read -p "input num1: " num1 read -p "input num2: " num2 if [ $num1 -gt $num2 ];then echo $num1 '>' $num2 elif [ $num1 -lt $num2 ];then echo $num1 '<' $num2 else echo $num1 '=' $num2 fi } 輸出結果: input num1: 1 input num2: 2 1 < 2
- case 選擇
case是常用的一種選擇結構,具體示例如下:#!/bin/bash usage() { echo "this is help!" } client() { echo "this is client!" } master() { echo "this is master!" } case "$1" in -h) usage ;; --help) usage ;; client) client ;; master) master $2 ;; *) echo "Unknown command: $1" usage exit 1 ;; esac #輸出結果: $ bash case_test.sh -h this is help! $ bash case_test.sh client this is client!
4.3 循環
- for 循環
shell中通過for實現循環,示例如下:function printarray(){ arr=(0 1 2 3 4 5 6) len=${#arr[@]} for (( i=0; i<$len; i++ )) do echo ${arr[$i]} done }
- while 循環
shell中通過while實現循環,示例如下:#!/bin/bash sum=0 i=0 while ((i<100)) do ((sum=sum+i)) ((i++)) done echo $i echo $sum
筆記5–函數
5.1 函數使用方法
shell中函數定義形式如下:
function functionName(){
cmd1
cmd2
}
其中,function可以省略;執行的時候直接functionName $para1 $para2即可。
5.2 shell常見函數
- 時間日期相關函數
- $ date
2020年 01月 20日 星期一 11:13:45 CST - $ date +"%Y%m%d"
20200120 - $ date +"%Y-%m-%d %H:%M:%S"
2020-01-20 11:17:09 - date +"%Y%m%d" -d “+n year|month|day” 今天的後n年|月|日 日期
- date +"%Y%m%d" -d “-n year|month|day” 今天的前n年|月|日 日期
- date +"%Y-%m-%d %H:%M:%S" -d “+n hour|minute|second” 今天的後 n時|分|秒 日期
- date +"%Y-%m-%d %H:%M:%S" -d “-n hour|minute|second” 今天的前 n時|分|秒 日期
- $ date
- to add …
筆記6–常見shell小功能
- 批量檢測 ip 是否ping通
#!/bin/bash abspath=$(cd "$(dirname "$0")"; pwd) logs=$abspath'/test_ping.log' iplist=(192.168.1.1 192.168.1.2 192.168.1.22) len=${#iplist[@]} for (( i=0; $i<$len; i++ )) do ping -c 2 ${iplist[$i]} &>/dev/null if [ $? -eq 0 ]; then echo -e "$(date) ${iplist[$i]} is up\t" >> $logs else echo -e "$(date) ${iplist[$i]} is down\t" >> $logs fi done
- 批量檢測用戶是否有 ssh 登錄權限
注意:需要使用ConnectTimeout、StrictHostKeyChecking、exit三個參數,否則會在相應界面等待輸入或佔用太長時間。ip.txt中存放所有ip,需按照行存放。tr -d '\r’主要爲了刪除換行符,否則在有些bash裏面執行ssh的時候會出現錯誤。function test_ssh(){ abspath=$(cd "$(dirname "$0")"; pwd) logs=$abspath'/test_ssh.log' iplist=$(cat ip.txt|tr -d '\r') for i in $iplist do ping -c 2 $i &>/dev/null if [ $? -eq 0 ]; then ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" -p yourport -l yourname $i exit if [ $? -eq 0 ]; then echo -e "[$(date)] [$i is connnected], [\$? $?]\t" >> $logs else echo -e "[$(date)] [$i is disconnected] [\$? $?]\t" >> $logs fi else echo -e "[$(date)] [$i is down] [\$? $?]\t" >> $logs fi done } 測試結果: [Sun 10 Nov 2019 11:14:04 AM CST] [xx is connnected], [$? 0] [Sun 10 Nov 2019 11:14:15 AM CST] [xx is down] [$? 0] [Sun 10 Nov 2019 11:14:26 AM CST] [xx is down] [$? 0] [Sun 10 Nov 2019 11:14:32 AM CST] [xx is disconnected] [$? 0]
- help 菜單實現方法
1)直接使用echo
todo…
2)使用EOF標識
todo…