什麼是Shelljava
操做系統最外層的程序,shell經過提示符讓用戶輸入,向操做系統解釋該輸入,而後處理來自操做系統的任何結果輸出來,管理用戶與操做系統之間的交互。node
Shell是一個用戶跟操做系統之間的一個命令解釋器。Shell是用戶與Linux操做系統之間溝通的橋樑。用戶能夠輸入命令執行,又能夠利用 Shell腳本編程去運行。python
爲何要用到shelllinux
shell是一個交互式程序,當用戶輸入一條命令,shell就解釋一條,一次只處理一條命令。若是咱們一些複雜操做,逐個敲命令工做量就會增大,所以,咱們能夠事先寫一個腳本,在腳本中寫入多條命令,讓shell一次性把這些命令全都執行完畢,而沒必要一條一條的敲shell
常見的shell種類編程
/bin/sh,/bin/csh,/bin/ksh,/bin/bash等,bash是大多數linux默認的shell程序,所以,在平常工做中被普遍使用vim
編程基礎:bash
程序:指定+數據dom
指令:由程序文件提供編程語言
數據:IO設備、文件、管道、變量等
程序編程風格:
過程式:以指令爲中心,數據服務於指令
對象式:以數據爲中心,指令服務於數據
編程語言:
強類型:必須實現聲明定義的變量及變量類型。如 java、python
弱類型:無需事先聲明變量,默認均爲字符串類型,可直接調用變量。如 shell
程序運行方式:
編譯運行:源代碼 --> 編譯器編譯 --> 可執行的二進制文件
解釋運行:源代碼 --> 運行時啓動解釋器,邊解釋邊運行
如何編寫shell腳本:
腳本文件的第一行,頂格:給出shebang,解釋器路徑,用於指明解釋執行當前腳本的解釋器程序文件
常見的解釋器:
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/python
編寫第一個shell腳本:
[root@CentOS6 bin]# cat first.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: first shell script echo "Hello,world" [root@CentOS6 bin]# bash first.sh Hello,world [root@CentOS6 bin]#
一個好的shell腳本會標明、做者、日期、版本、做用,這是一個良好的習慣,否則咱們代碼寫到百行的時候,過幾個月或幾年,回過頭來看,又能知道本身寫的是什麼腳本呢
如何運行shell腳本:
(1)賦予腳本文件執行權限,並直接運行腳本
chmod +x SCRIPT_FILE
./PATH/TO/SCRIPT_FILE
(2)直接運行解釋器,將腳本以命令參數傳遞給解釋器程序
bash /PATH/TO/SCRIPT_FILE
變量:指向內存的命令空間
變量名+指向的內存空間
變量賦值:VAR_NAME=value
變量類型:存儲格式、表示數據範圍、參與的運算
字符型
數值:整型、浮點型(shell不支持浮點型)
變量替換:把變量名出現的位置替換爲指定的內存空間中的數據
變量引用:${var_name},$var_name
變量名命名規則:
1.不能與系統中定義過的變量同名,不能與bash中的關鍵字同名,如 if case等等
2.只能包含數字、下劃線、字母
3.要作到見名只義
bash變量類型:
本地變量:僅對當前shell進程生效
環境變量:對當前shell以及子shell生效
局部變量:僅對shell進程中某一代碼片斷生效
位置變量:腳本執行時傳遞給腳本的參數
特殊變量:shell內置的有特殊功用的變量
本地變量:
變量賦值:name='value'
變量引用:${name},$name
"":變量名會被替換爲其值
'':變量名不會替換爲值,當作字符串來處理
查看變量:set
撤銷變量:unset var_name
環境變量:
變量賦值:
(1)export name='value'
(2)name='value'
export name
(3)declare -x name='value'
(4)name='value'
declare -x name
變量引用:${name},$name
查看環境變量:export、declare、env、printenv
撤銷變量:unset
bash有許多內置的環境變量:PATH,SHELL,USER,UID,GID,HISTSIZE,HISTFILESIZE,HOME,PWD,OLDPWD,HISTFILE,HISTCONTROL等
只讀變量:只能聲明,不可修改刪除
readonly var_name
declare -r var_name
位置變量:在執行腳本時,傳遞給腳本的參數
$1,$2,...${10}、${11}對應一、2個參數
特殊變量:shell內置變量
$?:存放上一條命令的執行狀態返回碼
$#:執行腳本時傳遞給腳本的參數個數
$*:傳遞給腳本的全部參數,會把這些參數當作一個字符串
$@:傳遞給腳本的全部參數,把每一個參數當作一個字符串來處理
$0:此腳本的名稱
$$:當前shell程序的PID
算術運算:
+, -, *, /, %, **
算術運算格式:
(1)let VAR=Expression
(2)VAR=$[Expression]
(3)VAR=$((Expression))
(4)VAR=$(expr $ARG1 $OP $ARG2)
(5)echo "Expression" | bc
bash內建隨機數生成器:$RANDOM(1-32767)
加強型賦值:+=, -=, *=, /=, %=
例如:let COUNT+=3
COUNT等於自身加3
自增,自減:
let var+=1
let var++
let var-=1
let var--
i++運算後加1,i--運算後減1
++i運算前加1,--i運算前減1
邏輯運算:
運算數:
true:真,用1表示
false:假,用0表示
與運算:兩個條件同時知足,則爲真
1 && 1 = 1
1 && 0 = 0
0 && 1 = 0
0 && 0 = 0
或運算:兩個條件有一個爲真,則爲真
1 || 1 = 1
1 || 0 = 1
0 || 1 = 1
0 || 0 = 0
非:取反
! 1 = 0
! 0 = 1
短路法則:
~]# COMMADN1 && COMMADN2
COMMADN1爲「假」,COMMADN2將不會執行
不然,COMMADN1爲「真」,COMMADN2必須執行
~]# COMMADN1 || COMMADN2
COMMAND1爲「真」,則COMMADN2不會被執行
不然,COMMADN1爲「假」,則COMMAND2必須執行
異或:^
異或的兩個值,相同爲假,不一樣則真
退出狀態碼:
進程使用退出狀態碼來報告命令的執行結果,成功或失敗
$?:上一條命令的執行狀態返回碼
成功:0
失敗:1-255
自定義狀態返回值:
exit#:#爲本身指定的狀態返回碼
注意:當腳本中遇到exit時,將終止整個腳本運行,默認是腳本中執行的最後一條命令的狀態返回值
條件測試:
判斷某個需求是都知足,若是知足則執行相應的操做,須要由測試機制來實現
如何編寫測試表達式以實現所需的測試:
(1)評估布爾聲明,以便用在條件測試中
若真,則返回0
若假,則返回非1
(2)測試表達式:
test EXPRESSION
[ EXPRESSION ]
` EXPRESSION `
注意:EXPRESSION先後兩端要有空格,不然報錯
bash測試類型:
數值測試:
字符串測試:
文件測試:
數值測試:數值比較
-eq:測試是否等於
-gt:是否大於
-lt:是否小於
-ge:是否大於等於
-le:是否小於等於
-ne:是否不等於
字符串測試:字符比較
==:測試字符是否相等
!=:是否不等於
=~:右側的字符是否能被左側的PATTERN所匹配
>:是否大於
<:是否小於
-z:測試指定字符串是否爲空,空爲真,不然爲假
-n:測試指定的字符串是否不不空,不空則真,不然爲假
注意:字符串比較實用` `
文件測試:
存在性測試:
[ -a FILE ]:測試文件是否存在
[ -e FILE ]
存在性及類型測試:
[ -b FILE ]:測試文件是否爲快設備文件
[ -c FILE ]:測試文件是否爲字符設備
[ -d FILE ]:測試文件是否爲目錄文件
[ -f FILE ]:測試文件是否爲普通ASCII文件
[ -p FILE ]:側是文件是否爲管道文件
[ -h FILE ]或[ -L FILE ]:測試文件是否爲符號連接文件
[ -S FILE ]:測試文件是否爲套接字文件
文件權限測試:
[ -r FILE ]:測試當前用戶是否對指定文件可讀
[ -w FILE ]:測試當前用戶是否對文件可寫
[ -x FILE ]:測試當前用戶是否對文件可執行
特殊權限測試:
[ -u FILE ]:測試文件是否具備SUID權限
[ -g FILE ]:測試文件是否具備SGID權限
[ -k FILE ]:測試文件是否有Sticky權限
測試文件中是否有內容:
[ -s FILE ]:測試文件中是否有內容,有爲真,不然假
時間戳:
[ -N FILE ]:文件自從上次讀取後是否被修改過
從屬關係測試:
[ -O FILE ]:測試當前用戶是不是文件的屬主
[ -G FILE ]:測試當前用戶是不是文件屬組
雙目測試:
[ FILE1 -ef FILE2 ]:FILE1與FILE2是否指向同一個文件系統的相同inode的硬連接
[ FILE1 -nt FILE2 ]:FILE1是否新於FILE2
[ FILE1 -ot FILE2 ]:FILE1是否舊於FILE2
組合條件測試:
第一種方式:
COMMAND1 && COMMAND2
COMMAND1 || COMMAND2
! COMMAND
[ -x FILE ] && [ -r FILE ]
第二種方式:
-a:與
-o:或
!:非
[ EXPRESSION1 -a EXPRESSION2 ]
[ EXPRESSION1 -o EXPRESSION2 ]
[ ! EXPRESSION ]
練習:
1.編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操做系統版本,內核版本,CPU型號,內存大小,硬盤大小。
[root@CentOS6 bin]# cat systeminfo.sh #腳本內容 #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 顯示當前系統信息包括主機名,IPv4地址,操做系統版本,內核版本,CPU型號,內存大小,硬盤大小 Hostname=$(hostname) IP=$(ifconfig | sed -n '2p' | cut -d: -f2 | cut -d' ' -f1) OS=$(lsb_release | grep "Description" | cut -d: -f2 | sed 's@^[[:space:]]\+@@') Kernel=$(uname -r) CPU=$(cat /proc/cpuinfo | grep "model name" | cut -d: -f2 | sed 's@^ @@') MEM=$(free -h | tr -s ' ' | cut -d' ' -f2 | sed -n '2p') DISK=$(fdisk -l | grep "Disk /dev/sd" | cut -d: -f2 | cut -d, -f1) echo -e "\033[32mShow system information.\033[0m" echo "Hostname: $Hostname" echo "IPv4 address: $IP" echo "OS version: $Kernel" echo "CPU model: $CPU" echo "Mem size: $MEM" echo "Disk size: $DISK" [root@CentOS6 bin]# vim systeminfo.sh [root@CentOS6 bin]# bash systeminfo.sh #運行結果 Show system information. Hostname: CentOS6.localdomain IPv4 address: 10.1.252.233 OS version: 2.6.32-642.el6.x86_64 CPU model: Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz Mem size: 980M Disk size: 107.4 GB [root@CentOS6 bin]#
2.編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
[root@CentOS6 bin]# cat backup.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 將/etc/目錄下的內容備份到/root/etcYYYY-mm-dd中 FILE="/root/etc`date +%F`" cp -rpf /etc/ $FILE echo "$FILE file backup finished." [root@CentOS6 bin]# bash backup.sh /root/etc2016-08-12 file backup finished. [root@CentOS6 bin]# ls -d ../etc2016-08-12/ ../etc2016-08-12/ [root@CentOS6 bin]#
3.編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
[root@CentOS6 bin]# cat disk.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 顯示當前硬盤分區中空間利用率最大的值 Max_Used=$(df -lhTP | sed -r 's@.* ([0-9]+%).*@\1@' | sed '1d' | sort | tail -1) echo "分區空間利用率最大爲$Max_Used" [root@CentOS6 bin]# bash disk.sh 分區空間利用率最大爲19% [root@CentOS6 bin]#
4.編寫腳本/root/bin/links.sh,顯示正鏈接本主機的每一個遠程主機的IPv4地址和鏈接數,並按鏈接數從大到小排序
[root@CentOS6 bin]# cat links.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 顯示正鏈接本主機的每一個遠程主機的IPv4地址和鏈接數,並按鏈接數從大到小排序 echo -e "當前鏈接本機的遠程主機IP\n" echo -e "鏈接次數 IP地址" netstat -tn | tr -s ' ' | cut -d' ' -f5 | cut -d: -f1 | sed '1,2d' | sort | uniq -c | sort -n -t' ' -k1 [root@CentOS6 bin]# bash links.sh 當前鏈接本機的遠程主機IP 鏈接次數 IP地址 2 10.1.250.60 3 10.1.253.23 [root@CentOS6 bin]#
5.寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
[root@CentOS6 bin]# cat sumid.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #descriptions: 計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和 FILE="/etc/passwd" ID_10=$(cat $FILE | sed -n '10p' | cut -d: -f3) ID_20=$(cat $FILE | sed -n '20p' | cut -d: -f3) SUMID=$[$ID_10+$ID_20] echo "$FILE file 10 user and 20 user uid sum is $SUMID." [root@CentOS6 bin]# [root@CentOS6 bin]# bash sumid.sh /etc/passwd file 10 user and 20 user uid sum is 180. [root@CentOS6 bin]#
6.寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
[root@CentOS6 bin]# cat sumfile.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件 ETC=$(ls -A /etc/ | wc -l) VAR=$(ls -A /var/ | wc -l) USR=$(ls -A /usr/ | wc -l) SUMFILE=$[$ETC+$VAR+$USR] echo "/etc/ /var/ /usr/ A total of $SUMFILE files" [root@CentOS6 bin]# [root@CentOS6 bin]# bash sumfile.sh /etc/ /var/ /usr/ A total of 296 files [root@CentOS6 bin]#
7.寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑做爲參數;若是參數個數小於1,則提示用戶「至少應該給一個參數」,並當即退出;若是參數個數不小於1,則顯示第一個參數所指向的文件中的空白行數
[root@CentOS6 bin]# cat argsnum.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 接受一個文件路徑做爲參數;若是參數個數小於1,則提示用戶「至少應該給一個參數」,並當即退出;若是參數個數不小於1,則顯示第一個參數所指向的文件中的空白行數 [ $# -lt 1 ] && echo "At least one parameter." && exit 1 SpaceLine=$(grep "^$" $1 | wc -l) echo "$1 spaceline is $SpaceLine." [root@CentOS6 bin]# [root@CentOS6 bin]# bash argsnum.sh #沒有給出參數,執行結果提示至少一個參數 At least one parameter. [root@CentOS6 bin]# bash argsnum.sh /etc/inittab #給出一個文件路徑,顯示此文件的空白行數 /etc/inittab spaceline is 8. [root@CentOS6 bin]#
8.寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址作爲參數,測試是否可連通。若是能ping通,則提示用戶「該IP地址可訪問」;若是不可ping通,則提示用戶「該IP地址不可訪問」
[root@CentOS6 bin]# cat hostping.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 接受一個主機的IPv4地址作爲參數,測試是否可連通。若是能ping通,則提示用戶「該IP地址可訪問」;若是不可ping通,則提示用戶「該IP地址不可訪問」 [ $# -lt 1 ] && echo "At least one parameter." && exit 1 ping -c 1 -W 1 $1 &> /dev/null && echo "$1 IP accessible" || echo "$1 IP not accessible." [root@CentOS6 bin]# [root@CentOS6 bin]# bash hostping.sh 10.1.1.1 10.1.1.1 IP not accessible. #IP不可訪問 [root@CentOS6 bin]# [root@CentOS6 bin]# bash hostping.sh 10.1.252.233 10.1.252.233 IP accessible #IP可訪問 [root@CentOS6 bin]#
9.chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫
[root@CentOS6 /]# cat per.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫 FILE="/tmp/file1" [ ! -r $FILE -a ! -w $FILE ] && echo "yes" || echo "no" #若是不可讀也不可寫,則輸出yes,不然輸出no [root@CentOS6 /]# [root@CentOS6 /]# ll /tmp/file1 #首先查看/tmp/file1文件的權限,爲640 -rw-r-----. 1 root root 0 Aug 11 22:43 /tmp/file1 [root@CentOS6 /]# [root@CentOS6 /]# bash per.sh no #root用戶對此文件可讀寫,輸出no [root@CentOS6 /]# su - zhai #切換至其餘用戶 [zhai@CentOS6 ~]$ whoami zhai [zhai@CentOS6 ~]$ bash /per.sh yes #zhia用戶對此文件不可讀也不可寫,輸出yes [zhai@CentOS6 ~]$
10.編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登陸系統。
用戶不可登陸nologin [root@CentOS6 bin]# cat nologin.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 實現禁止普通用戶登陸系統 FILE="/etc/nologin" ([ ! -e $FILE ] && touch $FILE && echo "create $FILE finished. ") || echo "$FILE exists." #判斷/etc/nologin文件是否存在,若是不存在,則建立 [root@CentOS6 bin]# bash nologin.sh create /etc/nologin finished. #提示建立文件成功,此時普通用戶已經不可登陸系統了 [root@CentOS6 bin]#
用戶可登陸login [root@CentOS6 bin]# cat login.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 實現容許普通用戶登陸系統 FILE="/etc/nologin" ([ -e $FILE ] && rm -rf $FILE && echo "delete $FILE finished.") || echo "$FILE not exists." #判斷/etc/nologin文件是否存在,若是存在就刪除 [root@CentOS6 bin]# [root@CentOS6 bin]# bash login.sh delete /etc/nologin finished. #提示刪除文件完成,此時普通用戶就能夠登陸到系統了 [root@CentOS6 bin]#
11.寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址作爲參數,先判斷是否合格IP,否,提示IP格式不合法並退出,是,測試是否可連通。若是能ping通,則提示用戶「該IP地址可訪問」;若是不可ping通,則提示用戶「該IP地址不可訪問」
[root@CentOS6 bin]# cat hostping.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址作爲參數,先判斷是否合格IP,否,提示IP格式不合法並退出,是,測試是否可連通。若是能ping通,則提示用戶「該IP地址可訪問」;若是不可ping通,則提示用戶「該IP地址不可訪問」 [ $# -lt 1 ] && echo "At least one parameter." && exit 1 echo "$1" | grep -E -q "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-1][0-9]|22[0-3])\>\.(\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>\.){2}\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>" RETVAL=$? [ $RETVAL -ne 0 ] && echo "$1 not is IP address." && exit 5 (ping -c 1 -W 1 $1 &> /dev/null && echo "$1 IP accessible") || (echo "$1 IP not accessible" && exit 7) [root@CentOS6 bin]# [root@CentOS6 bin]# bash hostping.sh 255.1.1.1 #給定非IP地址 255.1.1.1 not is IP address. [root@CentOS6 bin]# bash hostping.sh 10.1.252.255 #給定正確IP地址 10.1.252.255 IP accessible #此IP可訪問 [root@CentOS6 bin]# bash hostping.sh 10.1.252.252 10.1.252.252 IP not accessible #此IP不可訪問 [root@CentOS6 bin]#
12.計算1+2+3+…+100的值
[root@CentOS6 bin]# cat sum2.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 計算1到100之間全部整數之和 SUM=$(echo {1..100} | tr ' ' '+' | bc) echo "1到100之間的全部整數之和爲$SUM." [root@CentOS6 bin]# [root@CentOS6 bin]# bash sum2.sh 1到100之間的全部整數之和爲5050. [root@CentOS6 bin]#
13.計算從腳本第一參數A開始,到第二個參數B的全部數字的總和,判斷A是否大於B,否提示錯誤並退出,是則計算
[root@CentOS6 bin]# cat sum3.sh #!/bin/bash #author: xiaozhai #version: 1.0 #date: 2016-8-11 #description: 計算從腳本第一參數A開始,到第二個參數B的全部數字的總和,判斷B是否大於A,否提示錯誤並退出,是則計算之 [ $# -ne 2 ] && echo "Unknown Argument." && exit 1 ! expr $1 + $2 &> /dev/null && echo "Non integer parameter." && exit 2 [ $1 -gt $2 ] && echo "$1 greater $2." && exit 3 SUM=$(seq $1 $2 | tr '\n' ' ' | tr ' ' '+' | sed -r 's@\+$@\n@' | bc) echo "$1至$2之間全部整數之和爲$SUM." [root@CentOS6 bin]# [root@CentOS6 bin]# bash sum3.sh #腳本後不跟參數,提示未知參數 Unknown Argument. [root@CentOS6 bin]# bash sum3.sh 1 a #給出的參數不是整數 Non integer parameter. [root@CentOS6 bin]# bash sum3.sh 10 1 #$1大於$2 10 greater 1. [root@CentOS6 bin]# bash sum3.sh 1 99 #正確執行腳本 1至99之間全部整數之和爲4950. [root@CentOS6 bin]#