編譯型語言:node
程序在執行以前須要一個專門的編譯過程,把程序編譯成 爲機器語言文件,運行時不須要從新翻譯,直接使用編譯的結果就好了。程序執行效率高,依賴編譯器,跨平臺性差些。如C、C++正則表達式
解釋型語言:shell
程序不須要編譯,程序在運行時由解釋器翻譯成機器語言,每執 行一次都要翻譯一次。所以效率比較低。好比Python/JavaScript/ Perl /ruby/Shell等都是解釋型語言。vim
總結:數組
編譯型語言比解釋型語言速度較快,可是不如解釋性語言跨平臺性好。若是作底層開發或者大型應用程序或者操做系開發通常都用編譯型語言;若是是一些服務器腳本及一些輔助的接口,對速度要求不高、對各個平臺的兼容性有要求的話則通常都用解釋型語言。ruby
回顧一下,Linux操做系統由什麼組成的?bash
內核、shell、應用程序、文件系統服務器
shell:命令解釋器 人機交互的一個橋樑網絡
終端——》命令socket
|
bash shell 解釋器(shell)
|
kernel
|
硬件
什麼是shell腳本?
簡單來講就是將須要執行的命令保存到文本中,按照順序執行它。它是解釋型的,意味着它不須要編譯。
若干命令 + 腳本的基本格式 + 腳本特定語法 + 思想= shell腳本
何時用到腳本?
重複化、複雜化的工做,經過把工做的命令寫成腳本,之後僅僅須要執行腳本就能完成這些工做。
如何學習腳本?
一、儘量記憶更多的命令
二、掌握腳本的標準的格式(指定魔法字節、使用標準的執行方式運行腳本)
三、必須熟悉掌握腳本的基本語法(如下列表僅僅的基本要求,還有不少更深更難的語法須要本身擴充學習)
變量定義
條件判斷
分支語句
函數
數組
循環語句
正則表達式
sed,awk命令的使用
學習腳本的祕訣:
多看,多寫,多思考
看懂腳本——>模仿——>本身寫
腳本的編寫方法:
非標準:
source xxx.sh
. xxx.sh
bash xxx.sh
sh xx.sh
標準:
格式相對完整的腳本,建議的格式。
#!/bin/bash 腳本第一行 , #!魔法字符,指定腳本代碼執行的程序。即它告訴系統這個腳本須要什麼解釋器來執行,也就是使用哪種Shell
。。。。
腳本執行方法:
標準腳本執行方法(建議):(魔法字節指定的程序會生效)
非標準的執行方法(不建議):(魔法字節指定的程序不會運做)
總結:
./xxx.sh --要求有執行權限,而且必定要聲明shell類型(#!/bin/bash)
. xxx.sh或者source xxx.sh或者bash xxx.sh或者sh xxx.sh --不須要有執行權限,也能夠不聲明shell類型
說明: bash -x xxx.sh 或者sh -x xxx.sh --能夠顯示執行過程,幫助排錯
補充:
bash中的引號:
雙引號 "" 會把引號的內容當成總體來看待,容許經過$符號引用其餘變量值
單引號 '' 會把引號的內容當成總體來看待,禁止引用其餘變量值,shell中特殊符號都被視爲普通字符
反撇號 `` 和$() 反撇號和括號裏的命令會優先執行,若是存在嵌套,反撇號不能用。
; 可對一行命令進行分割,在執行過程當中不考慮上一個命令執行是不是正確的
&& 邏輯與。可對一行命令進行分割,在執行過程當中考慮上一個命令執行是不是正確的
|| 邏輯或
變量的分類:
本地變量:當前用戶自定義的變量。當前進程中有效,其餘進程及當前進程的子進程無效。
unset a 取消變量
環境變量:當前進程有效,而且可以被子進程調用。
HI=hello 設置一個本地變量
查看當前用戶的環境變量 env
env |grep HI
查詢當前用戶的全部變量<臨時變量與環境變量>
set |grep HI
HI=hello
export HI 將當前變量變成環境變量
env |grep -i HI
HISTSIZE=1000
HI=hello
全局變量:全局全部的用戶和程序都能調用,且繼承,新建的用戶也默認能調用。
/etc/profile
HI=Hello
export HI
/etc/profile
/etc/bashrc
~/.bash_profile
~/.bash_bashrc
user——>login——>/etc/profile——>~/.bash_profile——>/etc/bashrc——>~/.bashrc——>~/.bash_logout
局部變量:
~/.bash_profile
...
注意:須要從新登陸才生效
$HOME/.bashrc 當前用戶固定變量 eg:別名
$HOME/.bash_profile 當前用戶的環境變量
/etc/bashrc 使用bash shell用戶全局變量
/etc/profile 使用全部shell的全局變量
系統變量(內置bash中變量) : shell自己已經固定好了它的名字和做用。$@,$*,$# ,$$ ,$? ,$0
$#:腳本後面接的參數的個數
$*:腳本後面全部參數
$@: 腳本後面全部參數
$?:上一條命令執行後返回的狀態,當返回狀態值爲0時表示執行正常,非0值表示執行異常或出錯
若退出狀態值爲0 表示命令運行成功
若退出狀態值爲127 command not found
若退出狀態值爲126 找到了該命令但沒法執行 ---權限不夠
若退出狀態值爲1&2 沒有那個文件或目錄
$$ 當前所在進程的進程號
$! 後臺運行的最後一個進程號 (當前終端)
!$ 調用最後一條命令歷史中的參數
!! 調用最後一條命令歷史
$0 當前執行的進程/程序名
$1~$9 位置參數變量
${10}~${n} 擴展位置參數變量 第10個位置變量必須用{}大括號括起來
vim 3.sh
#!/bin/bash
#xxxxx
echo "\$0 = $0"
echo "\$# = $#"
echo "\$ = $"
echo "\$@ = $@"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo "\$10 = ${10}"
何時用到變量?
若是某個內容須要屢次使用,而且在代碼中重複出現,那麼能夠用變量表明該內容。這樣在修改內容的時候,僅僅須要修改變量的值
在代碼運做的過程當中,可能會把某些命令的執行結果保存起來,後續代碼須要使用這些結果,就能夠直接使用這個變量
變量定義的規則:
一、默認狀況下,shell裏定義的變量是不分類型的,能夠給變量賦與任何類型的值;等號兩邊不能有空格,對於有空格的字符串作爲賦值時,要用引號引發來
955 A=hello
956 echo $A
957 A= hello
958 A =hello
959 A = hello
960 A=hello world
961 A='hello world'
962 echo $A
963 A="hello world"
964 echo $A
二、變量的獲取方式: $變量名 ${變量名}
966 echo $A
967 echo ${A}
968 a=123456
969 echo $a
970 echo ${a}
971 echo ${a:2:3}
972 a=123456789
973 echo ${a:3:5} 3表明從第3位開始截取;5表明截取5個數
975 echo ${a:3} 表明截取從第3位開始之後全部的
三、取消變量的命令 unset 變量名
四、區分大小寫,同名稱但大小寫不一樣的變量名是不一樣的變量
五、變量名能夠是字母或數字或下劃線,可是不能以數字開頭或者特殊字符
[root@node1 shell01]# a=1abc
[root@node1 shell01]# 1a=hello
bash: 1a=hello: command not found
[root@node1 shell01]# ?a=hello
bash: ?a=hello: command not found
[root@node1 shell01]# /a=hello
bash: /a=hello: No such file or directory
[root@node1 shell01]# _a=777
[root@node1 shell01]# echo $_a
777
六、命令的執行結果能夠保存到變量
注意:
$( ) 等同於 執行符號 `,可是若是要嵌套使用,使用
符號就不行,要用$();但若是不是嵌套的使用
是能夠的,如a="
which mount`which yum
"
七、數組
數組定義:用括號來表示數組,數組元素用「空格」符號分割開。定義數組的通常形式爲:
array=(var1 var2 var3 var4)
或者
array[0]=v1
array[1]=v2
array[3]=v3
讀取數組:
${array [i]} i表示元素
使用@ 或 * 能夠獲取數組中的全部元素:
hello,stu1
hello,stu2
hello,stu3
#!/bin/bash
array=(stu1 stu2 stu3)
for var in ${array[*]}
do
echo hello,$var
done
[root@node1 shell01]# var[0]=user1
[root@node1 shell01]# var[1]=user2
[root@node1 shell01]# var[2]=user3
[root@node1 shell01]# for i in ${var[@]};do echo hello,$i;done
hello,user1
hello,user2
hello,user3
獲取第n個元素
echo "${user[N-1]}"
獲取數組指定元素
echo ${user[@]:1:3} 從數組下標爲1開始,讀取3個元素
示例:
定義一組用戶u01~u05,分別在屏幕上顯示hello,username
八、有類型變量
declare
-i 將變量當作整數
-r 使變量只讀 readonly
-x 標記變量經過環境導出 export
-a 將變量當作數組
[root@node1 shell01]# a=10
[root@node1 shell01]# b=2
[root@node1 shell01]# c=$a+$b
[root@node1 shell01]# echo $c
10+2
[root@node1 shell01]# declare -i a=5
[root@node1 shell01]# declare -i b=2
[root@node1 shell01]# declare -i c=$a+$b
[root@node1 shell01]# echo $c
7
[root@node1 shell01]#
[root@node1 shell01]# declare -i a=10 b=2
[root@node1 shell01]# declare -i c=$a*$b
[root@node1 shell01]# echo $c
20
1040 echo $a
1041 declare -r a=hello
1042 echo $a
1043 declare -r A=hello
1044 A=888
1045 echo $A
1046 declare -i A=123
1047 AB=hello
1048 export AB
1049 env|grep AB
1050 declare -x ABC=hahaha
1051 env|grep ABC
九、交互式定義變量的值 read 主要用於讓用戶去定義變量值
1054 read -p "Input your name:" name
1055 echo $name
1056 read -s -p "Input your password:" pass
1057 echo $pass
1058 read -n 5 -p "Input your name:" name
1059 echo $name
1060 read -t 3 -p "Input your name:" name
1061 echo $name
1062 read -t 3 -p "Input your name:" name
1063 echo $name
十、其餘變量:
一個「#」表明從左往右去掉一個指定字符
兩個「#」表明從左往右最大去掉指定字符
一個「%」表明從右往左去掉一個指定字符
兩個「%」表明從右往左最大去掉指定字符
取出一個目錄下的目錄和文件
/root/Desktop/shell/mem.txt
/root/Desktop/shell
mem.txt
/root/Desktop/shell
/root/Desktop/shell/mem
/root/Desktop/shell/mem
mem.txt
Desktop/shell/mem.txt
1071 aaa=/shell/shell01/dir1/file.txt
1072 echo $aaa
1073 dirname $aaa
1074 basename $aaa
1075 echo ${aaa#/*/}
1076 echo ${aaa##/*/}
1077 echo ${aaa%.*}
1078 echo ${aaa%%.*}
1079 echo ${aaa%/*/}
1080 echo ${aaa%/*}
1081 echo ${aaa%%/*}
===變量內容的替換===
[root@vm1 Desktop]# a=www.taobao.com
[root@vm1 Desktop]# echo ${a/taobao/baidu}
www.baidu.com
[root@vm1 Desktop]# a=www.taobao.com
[root@vm1 Desktop]# echo ${a/a/A}
www.tAobao.com
[root@vm1 Desktop]# echo ${a//a/A} 貪婪替換
www.tAobAo.com
===變量的替代===
aaaaa
111
${變量名:-新的變量值}
變量沒有被賦值(包括空值):都會使用「新的變量值「 替代
變量有被賦值: 不會被替代
簡單的四則運算
算術運算:
默認狀況下,shell就只能支持簡單的整數運算
$(()) | $[] | expr | let
Bash shell 的算術運算有四種方式:
一、使用 $(( ))
二、使用$[ ]
三、使用 expr 外部程式
四、使用let 命令
加法:
n=10
let n=n+1
或者let n+=1
echo $n
乘法:
let m=n*10
echo $m
除法:
let r=m/10
echo $r
求餘數:
let r=m%7
echo $r
乘冪:
let r=m**2
echo $r
注意:
n=1
let n+=1 等價於let n=n+1
思考:能不能用shell作小數運算?
2.5
i++ 和 ++i (瞭解)
對變量的值的影響:
[root@vm1 Desktop]# i=1
[root@vm1 Desktop]# let i++
[root@vm1 Desktop]# echo $i
2
[root@vm1 Desktop]# j=1
[root@vm1 Desktop]# let ++j
[root@vm1 Desktop]# echo $j
2
對錶達式的值的影響:
[root@vm1 Desktop]# unset i j
[root@vm1 Desktop]# i=1
[root@vm1 Desktop]# j=1
[root@vm1 Desktop]# let x=i++ 先賦值,再運算
[root@vm1 Desktop]# echo $i
2
[root@vm1 Desktop]# echo $x
1
[root@vm1 Desktop]# let y=++j 先運算,再賦值
[root@vm1 Desktop]# echo $j
2
[root@vm1 Desktop]# echo $y
2
條件判斷
語法結構:
if [ condition ];then
command
command
fi
if [ condition ];then
command1
else
command2
fi
if [ condition1 ];then
command1 結束
elif [ condition2 ];then
command2 結束
else
command3
fi
若是條件1知足,執行命令1後結束;若是條件1不知足,再看條件2,若是條件2知足執行命令2;若是條件1和條件2都不知足執行命令3.
if [ condition1 ];then
command1
if [ condition2 ];then
command2
fi
else
if [ condition3 ];then
command3
elif [ condition4 ];then
command4
else
command5
fi
fi
若是條件1知足,執行命令1;若是條件2也知足執行命令2,若是不知足就只執行命令1結束;
若是條件1不知足,不看條件2;直接看條件3,若是條件3知足執行命令3;若是不知足則看條件4,若是條件4知足執行命令4;不然執行命令5
判斷語法:
一、test 條件表達式
二、[ 條件表達式 ]
三、[[ 條件表達式 ]] 匹配正則 =~
#!/bin/bash
aaa=$1
[[ $aaa = 'hello' ]] && echo world
[root@node1 shell01]# bash -x if3.sh
aaa=
if3.sh: line 3: [: =: unary operator expected
[root@node1 shell01]# bash -x if3.sh hello
aaa=hello
'[' hello = hello ']'
world
[root@node1 shell01]# vim if3.sh
[root@node1 shell01]# bash -x if3.sh
aaa=
man test去查看,不少的參數都用來進行條件判斷
與文件存在與否的判斷
-e 是否存在 不論是文件仍是目錄,只要存在,條件就成立
-f 是否爲普通文件
-d 是否爲目錄
-S socket
-p pipe
-c character
-b block
-L 軟link
文件權限相關的判斷
-r 當前用戶對其是否可讀
-w 當前用戶對其是否可寫
-x 當前用戶對其是否可執行
-u 是否有suid
-g 是否sgid
-k 是否有t位
-s 是否爲空白文件 說明:-s表示非空,! -s 表示空文件
[ -s file1 ] file1文件內容不爲空,條件成立
[ ! -s file1 ] file1文件內容爲空,條件成立
兩個文件的比較判斷
file1 -nt file2 比較file1是否比file2新
file1 -ot file2 比較file1是否比file2舊
file1 -ef file2 比較是否爲同一個文件,或者用於判斷硬鏈接,是否指向同一個inode
整數之間的判斷
-eq 相等
-ne 不等
-gt 大於
-lt 小於
-ge 大於等於
-le 小於等於
字符串之間的判斷
-z 是否爲空字符串 字符串長度爲0,就成立
-n 是否爲非空字符串 只要字符串非空,就是成立
string1 = string2 是否相等
string1 != string2 不等
! 結果取反
多重條件判斷
邏輯判斷符號:
-a 和 && 邏輯與 [ 條件1 -a 條件2 ] 只有兩個條件都成立,整個大條件才成立
[ 1 -eq 1 ] && [ 2 -ne 3 ]
[ 1 -eq 1 -a 2 -ne 3 ]
-o 和 || 邏輯或 [ 條件1 -o 條件2 ] 只要其中一個條件成立,整個大條件就成立
[ 1 -eq 1 -o 2 -ne 2 ]
[ 1 -eq 1 ] || [ 2 -ne 2 ]
! 邏輯非 優先級最低
-a 優先級 比 -o 優先級要高
#!/bin/bash
aaa=id -u
[ $aaa -eq 0 ] && echo "當前是超級用戶" || echo "you不是超級用戶"
$ [ $UID -eq 0 ] && echo "當前是超級用戶" || echo "you不是超級用戶"
demo1:
判斷一個IP是否通ping通
方法1:
#!/bin/bash
read -p "請輸入你要ping額IP地址:" ip
ping -c1 $ip &>/dev/null 或者 >/dev/null 2>&1
if [ $? -eq 0 ];then
echo "當前主機與所輸入的IP網絡ok"
else
echo "當前主機與所輸入的IP網絡不ok"
fi
方法2:
ping -c1 $1 &>/dev/null
test $? -ne 0 && echo "當前主機與所輸入的IP網絡不ok" || echo "當前主機與所輸入的IP網絡ok"
demo2:
判斷一個進程是否存在
一、ps -ef|grep vsftpd |grep -v grep
二、pidof 程序名稱
三、pgrep -l 程序名稱
#!/bin/bash
ps -ef|grep vsftpd|grep -v grep &>/dev/null
if [ $? -eq 0 ];then
echo "該進程存在"
else
echo "該進程不存在"
fi
read -p "請輸入你須要判斷的進程名字:" name
pidof $name &>/dev/null
[ $? -eq 0 ] && echo "該進程存在" || echo "該進程不存在"
pidof $1 &>/dev/null
test $? -ne 0 && echo "該進程不存在" || echo "該進程存在"
需求:使用該腳本判斷所輸入的進程是否存在(多個進程名,至少2個)
#!/bin/bash
[ $# -eq 0 ] && echo "該腳本$0的用法是:$0 pidname" || pidname=($*)
for i in ${pidname[@]}
do
pidof $i &>/dev/null
test $? -ne 0 && echo "該進程不存在" || echo "該進程存在"
done
pgrep命令:以名稱爲依據從運行進程隊列中查找進程,並顯示查找到的進程id
選項
-o:僅顯示找到的最小(起始)進程號;
-n:僅顯示找到的最大(結束)進程號;
-l:顯示進程名稱;
-P:指定父進程號;pgrep -p 4764 查看父進程下的子進程id
-g:指定進程組;
-t:指定開啓進程的終端;
-u:指定進程的有效用戶ID。
demo3:
判斷一個服務是否正常(以httpd爲例):
一、能夠判斷進程是否存在,用/etc/init.d/httpd status判斷狀態等方法
二、最好的方法是直接去訪問一下,經過訪問成功和失敗的返回值來判斷
#!/bin/bash
wget -P /tmp http://localhost &>/dev/null
[ $? -eq 0 ] && echo "該服務正常" || echo "該服務不正常"
課堂練習:
一、寫一個腳本判斷一個用戶是否存在
二、完善上一個腳本的bug,要求當沒有給腳本傳參數或者參數個數不等於1個時,提示腳本的用法:usage:xxx.sh ip
#!/bin/bash
[ $# -ne 1 ] && echo "usage:basename $0
username" && exit
id $1 &>/dev/null
test $? -eq 0 && echo "該用戶$1存在" || echo "該用戶$1不存在"
#!/bin/bash
[ $# -ne 1 ] && echo "usage:basename $0
ipaddr" && exit
wget http://$1 &>/dev/null
[ $? -eq 0 ] && echo 'httpd服務正常' || echo "httpd服務不正常"
三、判斷vsftpd軟件包是否安裝,若是沒有則自動安裝
四、判斷vsftpd服務是否啓動,若是啓動,輸出如下信息:
vsftpd服務器已啓動...
vsftpd監聽的地址是:
vsftpd監聽的端口是:
#!/bin/bash
ftp=vsftpd
rpm -q $ftp &>/dev/null
[ $? -ne 0 ] && yum -y install $ftp &>/dev/null
pgrep -l $ftp &>/dev/null
[ $? -ne 0 ] && service $ftp start &>/dev/null && echo "服務已經啓動..."
ip=netstat -nltp|grep $ftp|cut -d: -f1|cut -c21-
port=netstat -nltp|grep $ftp|cut -d: -f2|cut -d' ' -f1
echo "vsftpd監聽的地址是:$ip"
echo "vsftpd監聽的端口是:$port"
做業:
一、 判斷/tmp/run文件是否存在,若是不存在就創建,若是存在就刪除目錄裏全部文件
#!/bin/bash
dir=/tmp/run
[ -d $dir ] && rm -rf $dir/* || mkdir $dir
dir=/tmp/run
[ -f $dir ] && mv $dir $dir.bak
[ -d $dir ] && rm -rf $dir/* || mkdir $dir
二、 輸入一個路徑,判斷路徑是否存在,並且輸出是文件仍是目錄,若是是字符鏈接,還得輸出是有效的鏈接仍是無效的鏈接
#!/bin/bash
read -p "請輸入絕對路徑:" path
if [ -e "$path" -a -L "$path" ];then
echo "該文件是一個有效鏈接文件"
elif [ ! -e "$path" -a -L "$path" ];then
echo "該文件是一個無效鏈接文件"
elif [ -d $path ];then
echo "該文件是一個目錄"
elif [ -f $path ];then
echo "該文件是一個普通文件"
elif [ -e $path ];then
echo "其餘文件"
else
echo "路徑不存在"
fi
三、交互模式要求輸入一個ip,而後腳本判斷這個IP 對應的主機是否 能ping 通,輸出結果相似於:
Server 10.1.1.20 is Down! 最後要求把結果郵件到本地管理員root@localhost和mail01@localhost
四、寫一個腳本/home/program,要求當給腳本輸入參數hello時,腳本返回world,給腳本輸入參數world時,腳本返回hello。而腳本沒有參數或者參數錯誤時,屏幕上輸出「usage:/home/program hello or world」
#!/bin/bash
if [ "$1" = "hello" ];then
echo world
elif [ "$1" = "world" ];then
echo hello
elif [ $# -ne 1 ];then
echo "usage:$0 hello or world"
else
echo "usage:$0 hello or world"
fi
五、寫一個腳本自動搭建nfs服務
#!/bin/bash
#1.安裝軟件
#2.確認軟件是否安裝
#3.配置
#(1).新建共享目錄,授本地權限
#(2).發佈共享目錄/etc/exports
#4.啓動服務
#5.設置下次開機自動啓動
#配置網絡,測試網絡
ping -c 1 192.168.0.254 &> /dev/null && echo "##############網絡OK###############"
#配置network yum
rm -fr /etc/yum.repos.d/*
cat > /etc/yum.repos.d/dvd.repo << EOT
[base]
baseurl=ftp://192.168.0.254/rhel6_dvd
gpgcheck=0
EOT
#1.安裝軟件
yum -y install nfs* rpcbind &> /dev/null && echo "##############軟件安裝OK###############"
#2.xx
#3.配置
#(1).新建共享目錄,授本地權限
#read -p "請輸入你的共享目錄" dir
mkdir -p $1
chmod 777 $1 && echo "##############本地受權OK###############"