1. 程式人生 > >第七章,shell編程基礎

第七章,shell編程基礎

shell 腳本 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編程基礎