編程基礎
v程序:指令+數據
v程序編程風格:
過程式:以指令為中心,數據服務于指令(適合小型程序)
對象式:以數據為中心,指令服務于數據(適合大型程序)
vshell程序:提供了編程能力,解釋執行
程序的執行方式
v計算機:運行二進制指令;
v編程語言:
低級:匯編
高級:
編譯:高級語言–>編譯器–>目標代碼
java,C#
解釋:高級語言–>解釋器–>機器代碼
shell, perl, python
編程基本概念
v編程邏輯處理方式:
順序執行
循環執行
選擇執行
vshell編程:過程式、解釋執行
編程語言的基本結構:
數據存儲:變量、數組
表達式: a + b
語句:if
Shell腳本
shell腳本基礎
shell腳本是包含一些命令或聲明,并符合一定格式的文本文件
格式要求:首行shebang機制
#!/bin/bash(.sh后綴結尾)
#!/usr/bin/python(.py后綴結尾)
#!/usr/bin/perl(.pl后綴結尾)
shell腳本的用途有:
自動化常用命令
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
創建shell腳本
v第一步:使用文本編輯器來創建文本文件
第一行必須包括shell聲明序列:#!
#!/bin/bash
添加注釋
注釋以#開頭
v第二步:運行腳本
給予執行權限,在命令行上指定腳本的絕對或相對路徑
chmod +x /PATH/TO/SCRIPT_FILE
/PATH/TO/SCRIPT_FILE
直接運行解釋器,將腳本作為解釋器程序的參數運行
bash /PATH/TO/SCRIPT_FILE
運行腳本
讓通過配置文件定義的特性立即生效
(1) 通過命令行重復定義一次
(2) 讓shell進程重讀配置文件
#source /PATH//FROM/FILE
#. /PATH/FROM/FILE
改變.bash_profile里面PATH變量,使運行腳本的執行路徑改變
root用戶存放的PATH變量
PATH=$PATH:$HOME/bin
普通用戶存放的PATH變量 ,有個隱藏的目錄.local,如果不存在可以自己創建
PATH=$PATH:$HOME/.local/bin:$HOME/bin
shell腳本范例
v#!/bin/bash
v#author:wang
v#Version:1.0
v#Description:Thisscriptdisplayssomeinformationaboutyour#environment
echo"Greetings.Thedateandtimeare$(date)"echo"Yourworkingdirectoryis:$(pwd)"
腳本調試
vbash-n /path/to/some_script
檢測腳本中的語法錯誤
vbash-x /path/to/some_script
調試執行(也具有語法檢測功能)
會把執行過程顯示出來
+和++是層次結構,++是先執行的那層
變量
1.變量
PATH\PWD\USER\OLDPWD\HISTSIZE\HISTFILESIZE\SHELL\HOME\PS1\HISTCONTROL\HISTTIMEFORMAL\UID\HISTFILE
2.命名的內存空間
數據存儲方式:字符:
數值:整型,浮點型
布爾值:
3.變量類型
作用:1、數據存儲格式
2、參與的運算
3、表示的數據范圍
類型: 字符
數值:整型、浮點型
4.編程程序語言分類:
1).強類型:定義變量時必須指定類型、參與運算必須符合類型要求;調用未聲明變量會產生錯誤。如java,python
2).弱類型:無須指定類型,默認均為字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用。如:bash 不支持浮點數
5.變量命名法則:
1、不能使程序中的保留字:例如if,for;
2、只能使用數字、字母及下劃線,且不能以數字開頭
3、見名知義
4、統一命名規則:駝峰命名法(大駝峰StudentName,小駝峰studentName)
6.bash中變量的種類
1)分類標準:根據變量的生效范圍等標準
本地變量:生效范圍為當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效
echo里面表達的是在vartest.sh的腳本中有個localvar1的變量他的值為localvar1
#!/bin/bash
localvar1=haha
echo"vartest1.sh:localvar1=$localvar1"
此時echo$localvar1 沒有反應,這說明自己定義的腳本只能自己使用,只對當前shell有效
[root@localhost ~]# bash vartest1.sh
vartest1.sh:localvar1=haha
sleep 20
運行vartest1腳本的時候相當于在bash的子進程shell中,但是echo$localvar1是在bash進程中的,所以他們不是在一個shell進程中
本地變量不能給子進程使用的例子:
在自己的腳本顯示自己的變量,在自己的腳本顯示localvar1的變量
#!/bin/bash
Lacalvar2=xixi
echo "vartest2.sh:localvar2=$localvar2"
echo "vartest2.sh:localvar1=$localvar1"
sleep 10
在vartest1中去調用vartest2,此時vartest1和vartest2是父子關系
#!/bin/bash
Localvar1=haha
echo "vartest1.sh:localvar1=$localvar1"
./vartest2.sh
Sleep 10
在子進程中嘗試顯示父進程的變量顯示失敗
[root@localhost~]# ./vartest1.sh
vartest1.sh:localvar1=haha
vartest2.sh:localvar2=xixi
vartest1.sh:localvar1=
原因是因為本地變量不能給子進程使用
環境變量:生效范圍為當前shell進程及其子進程
局部變量:生效范圍為當前shell進程中某代碼片斷(通常指函數)
位置變量:$1, $2, …來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量:$?,$0, $*, $@, $#
2)本地變量
v變量賦值:name=‘value’,
v可以使用引用value:
(1)可以是直接字串;name=“root"
(2)變量引用:name=${command}
(3)命令引用:name=$(COMMAND)
v變量引用:${name}, $name
"":弱引用,其中的變量引用會被替換為變量值
'':強引用,其中的變量引用不會被替換為變量值,而保持原字符串
v顯示已定義的所有變量:set
v刪除變量:unset name
練習
v1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。
v2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
v3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
v4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
3)環境變量
v變量聲明、賦值:
export name=VALUE
declare -x name=VALUE
聲明完之后在腳本中顯示
v變量引用:$name, ${name}
像$ab這種就需要加大括號${a}b.
v顯示所有環境變量:export
env
printenv
v刪除:unset name
vbash有許多內建的環境變量:PATH, SHELL, USRE,UID,HISTSIZE, HOME, PWD, OLDPWD, HISTFILE, PS1
環境變量對子進程生效
4)只讀和位置變量
v只讀變量:常量,只能讀,但不能修改和刪除
readonlyname
declare-r name
一般是常量中會使用
declare–rx name 表示既是一個常量又是一個環境變量
但是隨shell進程終止而終止
v位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數
$1,$2, …:對應第1、第2等參數,shift [n]換位置
$0:命令本身
$*:傳遞給腳本的所有參數,全部參數合為一個字符串
$@:傳遞給腳本的所有參數,每個參數為獨立字符串
$#:傳遞給腳本的參數的個數
重點:$@ $* 只在被雙引號包起來的時候才會有差異
示例:判斷給出的文件的行數
linecount="$(wc-l$1| cut -d' ' -f1)"
echo"$1 has $linecountlines."
算術運算
vbash中的算術運算:help let
+, – , * , / , %取模(取余),**(乘方)
1.實現算術運算:
(1) let var=算術表達式
相等的表達方式:
let var =var*5
let var*=5
(2)var=$[算術表達式]
(3)var=$((算術表達式))
(4)var=$(expr arg1 arg2 arg3 …)
expr 1 + 2 屏幕上就出現3
expr $var + 2 屏幕就會出現數值
可以判斷變量是否為整數:expr $var +0 就可以了
[root@localhost ~]# var=111
[root@localhost ~]# expr $var + 0
111
[root@localhost ~]# echo $?
0
[root@localhost ~]# expr $var + 0&> /dev/null
[root@localhost ~]# echo $?
0
但是乘法的時候需要轉意:
[root@localhost ~]# expr 2 * 3
expr: syntax error
[root@localhost ~]# expr 2 \* 3
6
(5)declare –i var= 數值
[root@localhost ~]# declare -ii=100
[root@localhost ~]# declare -ij=200
[root@localhost ~]# declare -im=i+j
[root@localhost ~]# echo $m
300
(6)echo ‘算術表達式’| bc
vbash有內建的隨機數生成器:$RANDOM(1-32767)
echo $[$RANDOM%50] :0-49之間隨機數
如果要表示2-51:echo $[$RANDOM%50+2]
表示1-n:echo $[$RANDOM%N+1]
2.賦值
v增強型賦值:
+=,-=, *=, /=, %=
vletvarOPERvalue
例如:let count+=3
自加3后自賦值
[root@localhost ~]# echo $i
100
[root@localhost ~]# let i++
[root@localhost ~]# echo $i
101
[root@localhost ~]# let i–
[root@localhost ~]# echo $i
100
[root@localhost ~]# let ++i
[root@localhost ~]# echo $i
101
[root@localhost ~]# let –i
[root@localhost ~]# echo $i
100
v自增,自減:
letvar+=1
letvar++
letvar-=1
letvar—
[root@localhost ~]# i=100
[root@localhost ~]# let v=i++
[root@localhost ~]# echo $i
101
[root@localhost ~]# echo $v
100
練習
v練習1:寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
v練習2:寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
v練習3:寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
邏輯運算
vtrue,false
1,0
v與:
1與1= 1
1與0= 0
0與1 = 0
0與0 = 0
v或:
1或1= 1
1或0= 1
0或1= 1
0或0= 0
v非:!
!1 = 0
!0 = 1
v短路運算:
短路與:
第一個為0,結果必定為0;
第一個為1,第二個必須要參與運算;
短路或:
第一個為1,結果必定為1;
第一個為0,第二個必須要參與運算;
v異或:^
異或的兩個值相比 ,相同為假,不同為真
例如:#command1 && command2
command1為“假”,則command2 不會再執行
否則,command1為“真”,則command2必須執行
#command1 || command2
command1為“假”,則command2 必須執行
否則,command1為“真”,則command2不會再執行
要實現user1用戶不存在就添加用戶user1:id user1 || useradd user1
聚集命令
有兩種聚集命令的方法:
1)復合式
復合式:date; who | wc -l
命令會一個接一個地運行
先執行date,再執行who|wc -l
[root@localhost ~]# who
root pts/0 2016-08-13 14:17 (10.1.250.108)
[root@localhost ~]# date;who |wc -l
Sat Aug 13 18:26:19 CST 2016
1
2)子shell
子shell:(date;who | wc -l ) >>/tmp/trace
所有的輸出都被發送給單個STDOUT和STDERR
[root@localhost ~]# (date;who |wc-l) >>/tmp/trace
[root@localhost ~]# cat/tmp/trace
Sat Aug 13 18:28:23 CST 2016
1
兩個命令一起執行可以使用()
[root@localhost ~]# (date;who)|wc -l
2
退出狀態
v進程使用退出狀態來報告成功或失敗
0代表成功,1-255代表失敗
$? 變量保存最近的命令退出狀態
v例如:
$ping-c1 -W1 hostdown&>/dev/null
$echo$?
-c1為只發一個包;-W1為等待1秒,默認5秒(大寫w)。
退出狀態碼
vbash自定義退出狀態碼
exit [n]:自定義退出狀態碼; exit 100
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決于exit命令后面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決于腳本中執行的最后一條命令的狀態碼
exit例子:
假如編下面的腳本:
#!/bin/bash
echo xxx;(echo zzz ;exit)
echo yyy
就會顯示:
[root@localhost ~]# bash f2.sh
xxx
zzz
yyy
相當于在xxx下面調用一個子進程,子進程內容為echo yyy
條件測試
1)判斷某需求是否滿足,需要由測試機制來實現;
專用的測試表達式需要由測試命令輔助完成測試過程;
2)評估布爾聲明,以便用在條件性執行中
若真,則返回0
若假,則返回1
3)測試命令:
test EXPRESSION
[ EXPRESSION ](空格) [ $a = $b ] [ $a == $b ]
[[ EXPRESSION ]](空格)[[ $a = $b ]] [[ $a == $b ]]
盡量使用雙中括號
注意:EXPRESSION前后必須有空白字符
注意:測試命令中其實只要括號內有東西就為真(空格也算),不一定非得比較,[ “ “]其結果為真??梢圆榭匆粋€變量是否被定義過,沒被定義過的則為假。
4)條件性的執行操作符
v根據退出狀態而定,命令可以有條件地運行
&&代表條件性的ANDTHEN
||代表條件性的ORELSE
v例如:
$grep-qno_such_user/etc/passwd\
||echo'Nosuchuser'
Nosuchuser
$ping-c1-W2station1&>/dev/null\
>&&echo"station1isup"\
>||(echo'station1isunreachable';exit1)
station1isup
test命令
v長格式的例子:
$test"$A"=="$B" && echo"Stringsareequal"(比較字符串用==)
$test“$A”-eq “$B” &&echo"Integersareequal"(比較數字用-eq)
v簡寫格式的例子:
$["$A"=="$B"]&& echo"Stringsareequal"
$["$A"-eq"$B"]&& echo"Integersareequal"
1數值測試
-gt:是否大于;greaterthan
-ge:是否大于等于;greaterand equal
-eq:是否等于;equal
-ne:是否不等于;not equal
-lt:是否小于;less than
-le:是否小于等于;less anequal
2字符串測試
==:是否等于;
>:ascii碼是否大于ascii碼
<:是否小于
!=:是否不等于
=~:左側字符串是否能夠被右側的PATTERN所匹配
注意: 此表達式一般用于[[ ]]中;
-z "STRING":字符串是否為空,空為真,不空為假
-n "STRING":字符串是否不空,不空為真,空為假
注意:用于字符串比較時的用到的操作數都應該使用引號
字符串比較大于小于號必須轉義,即加反斜線。
字符串比較的順序是按ASCII表的順序的,大寫字母比小寫字母的值小。
練習
v1、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
[ $# -lt 1 ] && echo "至少給用戶一個參數" || grep'^$' $1 | wc -l
v2、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
ping -c1 -W1 $1 && echo "該用戶地址可以訪問" || echo "該ip地址不可以訪問"
v3、如果最大磁盤利用率大于百分之20,就報錯
maxuse=`df | grep "dev/sd" | tr -s ' ' ':' |cut -d: -f5 | sed's@%@@' | sort -n | tail -1`
max=20
[[ maxuse -ge max ]] && echo " wall disk will be full!"
3文件測試
1)存在性測試
-aFILE:同-e
-e FILE: 文件存在性測試,存在為真,否則為假;
2)存在性及類別測試
-bFILE:是否存在且為塊設備文件;
-cFILE:是否存在且為字符設備文件;
-d FILE:是否存在且為目錄文件;
-f FILE:是否存在且為普通文件;(存在為真)
-hFILE 或-LFILE:存在且為符號鏈接文件;
-pFILE:是否存在且為命名管道文件;
-SFILE:是否存在且為套接字文件;
3)文件權限測試:
-rFILE:是否存在且可讀
-wFILE: 是否存在且可寫
-xFILE: 是否存在且可執行
看一個目錄的權限要看實際權限,不能看———,root賬號權限對它是不起作用:
4)文件特殊權限測試:
-gFILE:是否存在且擁有sgid權限;
-uFILE:是否存在且擁有suid權限;
-kFILE:是否存在且擁有sticky權限;
5)文件大小測試:
-sFILE: 是否存在且非空;
非空為真,空為假
6)文件是否打開:
-tfd : fd表示文件描述符是否已經打開且與某終端相關
-NFILE:文件自上一次被讀取之后是否被修改過(讀先發生,寫后發生)就是讀的時間比較舊
-OFILE:當前有效用戶是否為文件屬主
-GFILE:當前有效用戶是否為文件屬組
7)雙目測試:
FILE1–ef FILE2 : FILE1與FILE2是否指向同一個設備上的相同inode(硬鏈接)
FILE1–nt FILE2 : FILE1是否新于FILE2;(修改的時間)
FILE1–ot FILE2 : FILE1是否舊于FILE2;(修改的時間)
8)組合測試條件
v第一種方式:
COMMAND1&& COMMAND2 并且
COMMAND1|| COMMAND2 或者
!COMMAND 非
如:[ -e FILE ] && [ -r FILE ]
v第二種方式:
EXPRESSION1-a EXPRESSION2 并且
EXPRESSION1-o EXPRESSION2 或者
!EXPRESSION
必須使用測試命令進行,即進行test或者[ ];
意思是只要主機名沒有定義或者主機名為默認就改為www
#[ -z “$HOSTNAME” -o $HOSTNAME "==\
"localhost.localdomain"] && hostname www.magedu.com
判斷/bin/cat是否為可執行文件,如果是就調用
#[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
練習
v1、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫
不管對文件設置什么權限對root用戶是不管用的,所以我們要去普通用戶查看
[ ! -r /tmp/file1 -a ! -w /tmp/file1 ] || echo "用戶對文件不可讀不可寫"
v2、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。
[ -f /etc/nologin ] && echo "已經禁止普通用戶登入" || (touch /etc/nologin; echo "禁止用戶登入" )
[ -f /etc/nologin ] && rm -rf/etc/nologin || echo "普通用戶本身就可以登入系統"
原創文章,作者:Jagger,如若轉載,請注明出處:http://www.www58058.com/35281