第七章,shell編程基礎
Linux學習從入門到打死也不放棄,完全筆記整理(持續更新)
http://blog.51cto.com/13683480/2095439
筆記整理開始時間:2018年4月12日11:37:35
本章內容:
編程基礎
腳本基本格式
變量
運算
條件測試
配置用戶環境
編程基礎:
程序:指令+數據
程序編程風格:
過程式:以指令為中心,數據服務於指令
面向過程就是分析出解決問題所需要的步驟,然後用函數把這些步驟
一步一步實現,使用的時候一個一個依次調用就可以了
對象式:以數據為中心,指令服務於數據
面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為
了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為
shell程序:提供了編程能力,解釋執行
是對一堆Linux命令的邏輯化處理
程序的的執行方法:
計算機:運行二進制指令
編程語言:
低級:匯編
高級:
編譯:高級語言-->編譯器-->目標代碼
在編譯時將代碼轉換成2進制
java,c#
解釋:高級語言-->解釋器-->機器代碼
在程序執行時才轉換成2進制
shell,perl,python
編程基本概念:
編程邏輯處理方式
順序執行,循環執行,選擇執行
shell編程:過程式,解釋執行
編程語言的基本結構:
各種系統命令的組合
數據存儲:變量、數組
表達式:a + b
語句:if
shell腳本基礎:
shell腳本:
包含一些命令或聲明,並符合一定格式的文本文件
格式要求:首行shebang機制
#!/bin/bash shell
#!/usr/bin/python python
#!/usr/bin/perl perl
shell腳本的用途有:
自動化常用命令
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
創建shell腳本:
第一步:使用文本編輯器來創建文本文件
第一行必須包括shell聲明序列:#!
#!/bin/bash
添加註釋
註釋以#開頭
第二步:運行腳本
給予執行權限,+x,在命令行上指定腳本的絕對或相對路徑
/root/hello
直接運行解釋器(bash),如:
bash /root/hello
cat ff115 |bash
PS:source 執行程序 表示腳本會在當前shell運行不開啟子進程
腳本規範:
1.第一行一般為調用使用的語言
2.程序名,避免更改文件名為無法,正確找到的文件
(如不要取名bash,或者其他存在的程序名)
3.版本號
4.更改後的時間
5.作者相關信息
6.該程序的作用。以及註意事項
7.最後是各版本的更新簡要說明
腳本基本結構
#!shebang
configuration_variables 配置變量
function_definitions 定義函數
main code 主要代碼
腳本調試:
檢測腳本中的語法錯誤
bash -n hello.world
如:
[root@sentos7 ~/bin]#bash -n ceshi
ceshi: line 2: unexpected EOF while looking for matching `"'
ceshi: line 7: syntax error: unexpected end of file
調試執行:
bash -x hello.world
PS:
bash -n 只檢查語法錯誤
如果是語法錯誤後續命令不執行
如果是命令not found 後續會繼續執行
bash -x +代表深度,直接執行+,被調用執行++
腳本內不支持別名,也無法添加別名
變量:命名的內存空間
數據存儲方式:
把程序中準備使用的數據賦給一個簡短、易於記憶的名字
類型:
字符型
數值:×××,浮點型
作用:
數據存儲
參與運算
表示數據範圍
強類型:
變量不經過強制轉換,它永遠是這個數據類型,不允許隱式的類型轉化。一般
定義變量時必須指定類型,參與運算必須符合類型要求;調用未聲明變量會
產生錯誤。
如jave c#
弱類型:
語言的運行時會隱式做數據類型轉換。無須指定類型,默認均為字符型,參
與運算會自動進行隱式類型轉換,變量無須事先定義可直接調用
如:bash不支持浮點數, php
變量命名法則:
1.不能使用程序中的保留字;例如:if ,for
2.只能使用數字、字母及下劃線,且不能以數字開頭
3.見名知義
4.統一命名規則:駝峰命名法
bash中變量的種類:
根據變量的生效範圍等標準等標準劃分下面變量類型:
局部變量:
生效範圍為當前shell進程;對當前shell之外的其他shell進程,
包括當前shell的子shell進程均無效
環境(全局)變量:
生效範圍為當前shell進程及其子進程
本地變量:生效範圍為當前shell進程中某代碼片段,通常指函數
位置變量:$1,$2,..${10}..來表示,用於讓腳本在腳本代碼中調用通過命令行傳遞
給它的參數
特殊變量:
$?,$0,$*,$@,$#,$$
$? 前一個命令的退出狀態,成功為0,不成功為非0
局部變量:
變量賦值:name='value'
可以使用引用value:
1.可以是直接字串; name=‘root’
2.變量引用: name=$USER
3.命令引用: name=`command`
name=$(cmd)
ps:
變量一旦賦值,除非重新賦值,否則所占內存空間不變,值不變
name1=name2的情況
就算賦值之後name2的值改變了,name1的值保持不變
i=100 賦值為字符,不問數字類型
變量引用:
${name} $name
"":弱引用,其中的變量引用會被替換為變量值,如
[root@sentos7 ~/bin]#echo "$PS1"
\[\e[1;35m\][\u@\h \w]\$\[\e[0m\]
'':強引用,其中的變量引用不會被替換為變量值,而保持原字符串
[root@sentos7 ~/bin]#echo '$PS1'
$PS1
顯示已經定義的所有變量:set
刪除變量: unset name
PS:
pstree -p 進程tree
echo $$ 當前進程的進程編號
echo $PPID 父進程的進程編號
練習1
? 1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,
IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小
? 2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到
/root/etcYYYY-mm-dd中
? 3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
? 4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址
和連接數,並按連接數從大到小排序
環境變量:
變量聲明,賦值:
export name=Value 相當於name=Value;export name
declare -x name2=Value
let c=name+name2;export c
變量引用:$name,${name2}
顯示所有環境變量:
env
printenv
export
declare -x
刪除變量:
unset name
bash內建的環境變量:
PATH:
SHELL:
USER:
UID:
HOME:
PWD:
SHLVL: 當前shell層數
LANG: 語言鍵盤、字符編碼
MAIL: 當前用戶mail目錄
HOSTNAME:
HISTSIZE:
_: 前一個命令的最後一個參數
只讀和位置變量:
只讀變量:只能聲明,但不能修改和刪除
聲明只讀變量:
readonly name
declare -r name
查看只讀變量:
readonly -p
位置變量:再腳本代碼中調用通過命令行傳遞給腳本的參數
$1,$2,..${10}..: 對應相應第1,2..10..個參數
腳本中命令:shift[n] 可以傳遞參數位置,如:
shift 可以將原本$2,變成$1
shift 3 將原$4變成$1
$0 命令本身,名字
默認帶路徑,可以用 `basename $0`取出來
$0 如果是軟鏈接的話 $0會顯示各自軟鏈接的名字
$* 傳遞給腳本的所有參數,全部參數合為一個字符串
$@ 傳遞給腳本的所有參數,每個參數為獨立字符串
$# 傳遞給腳本的參數的個數
$@ $* 在腳本調用腳本傳遞參數時,如果用"$*",會將所有參數當成一個
字符串傳遞
$* $@ "$@" 會將每個參數單獨傳遞
set -- 清空所有位置變量
退出狀態
進程使用退出狀態來報告成功或失敗
$? 保存最近的命令退出狀態
0 成功
1-255 失敗
例如:
ping -c1 172.20.3.14 &>/dev/null
echo $?
退出狀態碼:
bash 自定義退出狀態碼
exit [n] 自定義退出狀態碼
註意:
腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決於
exit命令後面的數字
如果沒有給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本
中執行的最後一條命令的狀態碼
算術運算:let
bash中的算術運算:help let
常用算術:
+,-,*,/,%(取模 取余),**(乘方),id++,id--,
實現算術運算的格式:
1. let var=算術表達式
let z=x+y;let x++;let y=x**2;
let z=(3*x+4*y/3)-2*x
2. var=$[算術表達式]
z=$[(3*x+4*y/3)-2*x]
3. var=$((算術表達式))
z=$(((3*x+4*y/3)-2*x))
4. var=$(expr arg1 arg2 arg3...)
如:z=$(expr $x + $y) 表示z=x+y
*需要寫成\*
5. declare -i var=數值(可以使是算式)
declare -i x=x+y
declare -i x=3*x+y*4/2
6. echo ’算術表達式‘ |bc
bash有內建的隨即數生成器:$RANDOM(0-32676)
echo $[$RANDOM%50]: 0-49之間隨機數
賦值:
增強型賦值:
+=,-=,*=,/=,%=
let x+=3;x-=1;x*=5;x/=4
+3 -1 *5 /4
shell不支持浮點計算,所以除法會有商整取余
自增,自減
let x+=1;let x++
let x-=1;let x--
練習2
1、編寫腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第
20用戶的ID之和
? 2、編寫腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計
算這兩個文件中所有空白行之和
? 3、編寫腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級
子目錄和文件
邏輯運算
與: &
或: |
非: !
!1=0
!0=1
短路運算:
cmd1 && cmd2
如果cmd1為假,cmd2不需要執行,反之cmd1為真,需要cmd2執行
cmd1 || cmd2
如果cmd1為真,cmd2不需要執行,反之cmd1為假,需要cmd2執行
cmd1 && cmd2 || cmd3 要求cmd2必真
cmd1為真,執行cmd2
為假,執行cmd3
異或:^ XOR
二進制運算,同為0 異為1
a=5;b=6;echo $a $b;a=$[a^b];b=$[a^b];a=$[a^b];echo $a $b
將a b的值互換
ture 和false
只返回真或者假,不做任何操作
true && echo hello
false && echo hello||echo nihao
條件測試:test
判斷某需求是否滿足,需要由測試機制來實現
專用的測試表達式需要由測試命令輔助完成測試過程
評估布爾聲明,以便用在條件性執行中
若真 則返回0
若假 則返回1
測試命令:
test expression 如:test a = b ;echo $?
[ $a = b ] && echo ture || echo false
[[ $a =~ pattern ]]
表達式epression 前後必須有空白字符
根據退出狀態而定,命令可以有條件的執行
&& 代表條件性的and then
|| 代表條件性的 or else
例如:
grep -q no_such_user /etc/passwd || echo 'NO such user'
id usera &>/dev/null && echo "usera is exist" || useradd usera
長格式的例子:
test "$A" == "$B" && echo "Strings are equal"
[ "$A" == "$B" ]
test "$A" -eq "$B" && echo "Integers are equal"
[ "$A" -eq "$B" ]
bash的數值測試:
-v var
變量是否設置 test -v var && echo hello||echo nihao
[ -v var ] && set || not set
PS:
此處使用變量var前不可加"$",否則判斷異常
數值測試:
-gt 是否大於 [ $A -gt $B ]
-ge 是否大於等於
-eq 是否等於
-ne 是否不等於
-lt 是否小於
-le 是否小於等於
bash的字符串測試:
== 是否等於 等於為真,0
> ascii碼是否大於ascii碼
< 是否小於
!= 是否不等於 不等於為真,0
=~ 左側字符串是否能夠被右側的pattern所匹配
註意:此表達式一般用於[[ ]]中,支持擴展的正則表達式
-z "string" 字符串是否為空,空為真,不空為假
-n "string" 字符串是否不空,不空為真,空為假
註意: 用於字符串比較時用到的操作數都應該使用引號
[[ ]]使用pattern時 表達式 不能加引號 ,也不能識別\< \> \b
判斷是否為空也可以:
[ x = x"$a" ] && echo ture || echo false
練習3:
1、編寫腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數
個數小於1,則提示用戶“至少應該給一個參數”,並立即退出;如果參數個數
不小於1,則顯示第一個參數所指向的文件中的空白行數
? 2、編寫腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測
試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可
ping通,則提示用戶“該IP地址不可訪問”
? 3、編寫腳本/root/bin/checkdisk.sh,檢查磁盤分區空間和inode使用率,如
果超過80%,就發廣播警告空間將滿
Bash的文件測試:
存在性測試:
-a file 同 -e
-e file 文件存在性測試,存在為真,否則為假
存在性及類別測試
-b file 是否存在且為塊設備文件
-c file 是否存在且為字符設備文件
-d file 是否存在且為目錄文件
-f file 是否存在且為普通文件
-h file 或 -L file 是否存在且為符號鏈接文件
-p file 是否存在且為命名管道文件
-S file 是否存在且為套接字文件
Bash的文件權限測試:
文件權限測試:
-r file 是否存在且可讀
-w file 是否存在且可寫
-x file 是否存在且可執行
文件特殊權限測試:
-u file 是否存在且擁有suid權限
-g file 是否存在且擁有sgid權限
-k file 是否存在且擁有sticky權限
Bash的文件屬性測試:
文件大小測試:
-s file 是否存在且為空
文件是否打開
-t fd:fd 文件描述符是否在某終端已經打開
-N file 文件自從上一次被讀取之後是否被修改過
-O file 當前用戶是否為文件屬主
-G file 當前有效用戶是否為文件屬組
雙目測試:
file1 -ef file2 file1是否是file2的硬鏈接
file1 -nt file2 file1是否新於file2 (mtime)
file1 -ot file2 file1是否舊與file2
Bash的組合測試條件:
第一種方式:
cmd1 && cmd2 且
cmd1 || cmd2 或
!cmd 非
如: [[ -r FILE ]] && [[ -w FILE ]]
第二種方式:
[ expression1 -a expression2 ] 並且
[ expression1 -o expression2 ] 或者
[ !expression ] 非
例:
[ -z "$HOSTNAME" -o "$HOSTNAME" == "localhost.localdomain" ] &&
hostname www.magedu.com
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
PS:
&&(-a) ||(-o)可連續使用
[ -r "$1" -a -w "$1" -a -x "$1" ] && echo ture || false
[ -a "$1" ] && [ -r "$1" ] && [ -w "$1" ] && [ -x "$1" ] && echo ture || false
只要有一個為假,就返回假
[ -r "$1" -o -w "$1” -o "$1" ] && echo ture || false
[ -r "$1" ] || [ -w "$1" ] || [ -x "$1"] && echo ture || false
只要一個為真,則返回為真
練習:?
1、編寫腳本/bin/per.sh,判斷當前用戶對指定參數文件,是否不可讀並且不可寫
? 2、編寫腳本/root/bin/excute.sh ,判斷參數文件是否為sh後綴的普通文件,如
果是,添加所有人可執行權限,否則提示用戶非腳本文件
? 3、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統
read:
使用read來把輸入值分配給一個或多個shell變量
-p 指定要顯示的提示,如:
read -p "Please input your name: " name
-s 靜默輸入,一般用於密碼,如:
read -s -p "Please input your password: " passw
-n N 指定輸入的字符長度N
指定長度之後,如達到長度,後續指令不會換行,直接在輸入的內容之後顯示了
想要達到換行的目的,需要下一行加上
echo "" 但是如果手動回車則會顯示一行空行
-d '字符' 輸入結束符 到此字符直接結束輸入
read -t 20 -n 20 -p "Please input you ID, end with'#' : " ID
與-n類似,也是不會換行
-t N TIMEOUT為N秒
timeout並不會退出腳本,而是會執行後續指令
read 如果從標準輸入中讀取值,給每個單詞分配一個變量
所有剩余單詞都被分配給最後一個變量
不支持管道接受標準輸入 | read name
bash如何展開命令行
把命令行分成單個命令詞
展開別名
展開大括號的聲明({})
展開波浪符聲明(~)
命令替換$()和(``)
再次吧命令行分成命令詞
展開文件通配(*、?、[abc]等等)
準備I/O重導向(<,>)
運行命令
防止擴展:
反斜線 \ 會使隨後的字符按原意解釋
$ echo your cost:\$5.00
your cost:$5.00
加引號來防止擴展
單引號'' 防止所有擴展
雙引號"" 也防止所有擴展,但是以下情況例外
$ --變量擴展
`` $() --命令替換
\ --禁止單個字符擴展
! --歷史命令替換
bash的配置文件:
按生效範圍劃分、存在兩類
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
個人配置:
~/.bash_profile
~/.bashrc
shell登錄兩種方式
交互式登錄:
1)直接通過終端輸入賬號密碼登錄
2)使用 su - username 切換的用戶
執行順序:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile -->
~/.bashrc --> /etc/bashrc
非交互式登錄:
1)su username
2)圖形界面下打開的終端
3)執行腳本
4)任何其他的bash實例
執行順序:~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
按功能劃分:
profile類:
為交互式登錄的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
個人:~/.bash_profile
功能:
用於定義環境變量
運行命令或腳本
bashrc類:
為交互式和非交互式登錄的shell提供配置
全局:/etc/bashrc
個人:~/.bashrc
功能:
定義命令別名和函數
定義本地變量
配置文件修改生效:
修改profile和bashrc文件後需生效
兩種方法:
重新啟動shell進程(重新登錄)
. 或 source
例如: . ~/.bashrc
Bash退出任務:
保存在~/.bash_logout文件中
在退出登錄shell時運行
用於:
創建自動備份
清楚臨時文件
變量:$-
h:hashall,打開這個選項後,shell
會將命令所在的路徑hash下來,避免每次都要查詢。通過set+h將h選項關閉
i:interactive-comments,包含這個選項說明當前的shell是一個交互式的shell
所謂的交互式shell,在腳本中,i選項都是關閉的
m:monitor,打開監控模式,就可以通過job control來控制進程的停止、繼續、
後臺或者前臺執行等。
B:braceexpand,大括號擴展
H:history,H選項打開,可以展開歷史列表中的命令,可以通過!來完成,
例如!!,返回最近的一個歷史命令,!n 返回第n個歷史命令
練習:
1、讓所有用戶的PATH環境變量的值多出一個路徑,例如:
/usr/local/apache/bin
? 2、用戶root登錄時,將命令指示符變成紅色,並自動啟用如下別名:
rm=‘rm –i’
cdnet=‘cd /etc/sysconfig/network-scripts/’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 或 ifcfg-ens33 ’ (如果系
統是CentOS7)
? 3、任意用戶登錄系統時,顯示紅色字體的警示提醒信息“Hi,dangerous!”
? 4、編寫生成腳本基本格式的腳本,包括作者,聯系方式,版本,時間,描述等
? 5、編寫用戶的環境初始化腳本reset.sh,包括別名,登錄提示符,vim的設置,
環境變量等
筆記整理完成時間:2018年4月13日16:58:39
第七章,shell編程基礎