初識shell腳本編程

shell腳本基礎

shell腳本是包含一些命令或聲明,并符合一定格式的文本文件

一般格式要求:

1.首行shebang機制

#!/bin/bash

#!/bin/python

#!/usr/bin/perl

2.注釋信息

以#開頭,可寫明腳本用途,作者,版本,時間等

3.腳本正文內容,

創建shell腳本

以bash為例

  1. 第一行定格#!/bin/bash

  2. 注釋信息:

    1. #用途

    2. #作者 

    3. #版本

    4. #時間

  3. 腳本正文內容,保存退出

  4. 給予腳本文件執行權限,

    1. 在命令上執行腳本的絕對路徑或相對路徑

    2. 直接運行解釋器,將腳本作為解釋器程序的參數運行

腳本范例

blob.png

blob.png

腳本調試

當我們寫完腳本時,可以使用指令檢測腳本中的語法錯誤

   bash  -n  /path/to/some_script  ==>檢測錯誤 

   bash  -x  /path/to/some_script  ==>調試執行

blob.png

blob.png

變量  :命令的內存空間

變量命名法則:

  1. 不能使用程序中的保留字:例如if,for ==>不能使用系統自帶的變量名

  2. 只能使用數字,字母及下劃線,且不能以數字開頭

  3. 見名知意

  4. 統一命名規則:駝峰命名法

變量種類


本地變量:生效范圍為當前shell進程;對當前shell之外的其他shell進程,包括當前shell的子shell進程均無效

blob.png

blob.png

blob.png

說明:腳本file1.sh定義變量num1,且腳本file2.sh是其子進程,腳本file2.sh中定義變量num2

運行file2.sh,變量num2有效顯示,變量num1未顯示,運行file1.sh,

變量num1有效顯示,變量num2未顯示,子進程file2.sh運行,變量num2有效顯示,變量num1未顯示

由以上可知,以上變量只在當前進程有效

環境變量:生效范圍為當前shell進程及其子進程

blob.png

blob.png

blob.png

說明:在上面本地變量的基礎上將變量類型改變成環境變量,執行效果也有差異

file2.sh是file.1sh的子進程,file1.sh中定義的變量file2.sh在作為其子進程運行時,

是有效果的,但是在file2.sh不作為file1.sh的子進程運行時,是沒效果的,看單獨運行

file2.sh中只有變量num2,而在運行file1.sh時,num2沒有繼承其子進程的變量

所以:生效范圍為當前shell進程及其子進程,其父進程也是不生效的

局部變量:生效范圍為當前shell進程中某代碼片段(通常指函數)

位置變量:$1,$2,…..來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數

特殊變量$?,$0,$*,$@,$#

本地變量:

變量賦值:name=‘value’

  1. 可以直接是字符串;name=“root”

  2. 變量引用:name="$USER"

  3. 命令引用:name=`command` ,name=$(command)

變量引用:${name} ,$name

    " " :弱引用,其中的變量引用會被替換為變量值    

   ‘ ’:強引用,其中的變量引用不會被替換為變量值,而保持原字符

顯示已定義的所有變量:set

刪除變量: unset  name

環境變量

變量賦值:    

    export name=VALUE

    declare -x name=VALUE

變量引用:${name} ,$name

顯示所有環境變量:

    export

    env    

    printenv

刪除變量: unset name

bash內建的環境變量:PATH,SHELL,USER,UID,HISTSIZE,HOME,PWD,OLPWD,PS1,HISTFILE

只讀變量:只能用,不能修改和刪除

readonly  name

declare  -r  name

可用來定義一些固定的值,直接引用,例如π

位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數

$1,$2,…:對應第1,2,….等參數

$0 :命令本身

$* :傳遞給腳本的所有參數,全部參數何為一個字符串

$@ :傳遞給腳本的所有參數,每個參數為獨立字符串

$# :傳遞給腳本的參數的個數

備注:$@ $* 只在被雙引號包起來的時候才會有差異(后面會專門驗證)

算數運算:

bash的算術運算: +,-,*,/,%取余,**(乘方)

實現算術運算:

  1. let var=算術表達式

  2. var=$[算術運算]

  3. var=$((算術運算))

  4. var=$(expr arg1  arg2  arg3 ….)

  5. declare -i var  =  數值

  6. echo  `算術表達式` |bc

乘法符號游戲場景中需要轉義:\*

bash 有內建的隨機數生成器:$RANDOM (1-32767) )

    echo $[$RANDOM%50]  :0-49 之間隨機數

blob.png

賦值

增強型賦值:

    變量做某種算數運算后會存至此變量中

    i=$[$i+1] ==>每運行一次此命令,變量i的值會增加1

    let i+=1 同上

    let i+=2每次增加2

    let(+=,-=,*=,/=,%=)

自增:

VAR=$[$VAR+1]

let VAR+=1

let VAR++

自減:

VAR=$[$VAR-1]

let VAR-=1

let VAR–

blob.png

邏輯運算

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

短路運算:

    短路與:

        第一個為0,結果必定為0

        第一個為1,第二個必須要參與運算

    短路或:

        第一個為1,結果必定為1

        第一個為0,第二個必須要參與運算

異或:^

    異或的兩個值相同為假,不同為真

聚集命令

復合式:date;who| wc -l

    命令會一個接一個的運行

子shell:(date;who|wc -l)>>/tmp/trace

    所有的輸出都被發送給單個的STDOUT和STDERR

退出狀態

進程使用退出狀態來報告成功或失敗

0:成功

1-255:失敗

$? :變量保存最近的命令退出狀態

 blob.png

退出狀態碼

bash自定義退出狀態碼

    exit [n] :自定義退出狀態碼

ps:腳本中一旦遇到exit命令,腳本會立即終止;終止狀態取決于exit命令后面的數字

   如果未給腳本指定退出狀態碼,整個腳本的推出狀態碼取決于腳本中執行的最后一條命令的狀態碼

條件測試

    判斷某需求是否滿足,需由測試機制來實現

    如何編寫測試表達式以實現所需的測試:

        1.執行命令,并利用命令的狀態返回值來判斷

            0:成功    

            1-255:失敗

        2.測試表達式

            test expression  比較大小

            [ expression ]    

            [[ expression ]]

        注意:expression兩端必須有空白字符,否則為語法錯誤

    

    根據退出狀態而定,命令可以有條件的運行

        && 代表條件性的AND THEN

        || 代表條件性的OR ELSE

        

        短路與: command1&&command2

                如果command1成功,執行command2

                如果command1失敗,不執行command2

  blob.png

        短路或:command1||command2

                如果command1成功,跳過command2

                如果command1失敗,將執行command2

blob.png                

test

長格式

test "$A" == "$B"&& echo "xiangdeng"

test "$A" -eq "$B" && echo "budengde"

簡寫格式

[ "$A" ==  "$B" ]&& echo "xiangdeng"

[ "$A" -eq "$B  ]&& echo "budengde"

blob.png

bash 測試類型

數值測試:

-gt:是否大于

-ge:是否大于等于

-eq:是否等于

-ne:是否不等于

-lt:是否小于

-le:是否小于等于

blob.png

字符串測試

== :是否等于

>  :ascii碼是否大于ascii碼

<  :ascii碼是否小于ascii碼

!=:ascii碼是否不等于ascii碼

=~ :左側字符串是否能夠被右側pattern所匹配

注意:此表達式一般用于[[ ]]中

-z “string”:字符串是否為空,空為真,不空為假

-n “string”:字符串是否不空,不空為真,空為假

注意:用于字符串比較時的用到的操作數都應該使用引號

[root@localhost ~]# A=bbb
[root@localhost ~]# B=aaa
[root@localhost ~]# C=aaa
[root@localhost ~]# [[ "$C" == "$B" ]]&& echo right
right
[root@localhost ~]# [[ "$C" == "$A" ]]&& echo right
[root@localhost ~]# [[ "$B" == "$A" ]]&& echo right
[root@localhost ~]# [[ "$B" == "$A" ]]&& echo right||echo wrong
wrong
[root@localhost ~]# [[ "$B" == "$c" ]]&& echo right||echo wrong
wrong
[root@localhost ~]# [[ "$B" == "$C" ]]&& echo right||echo wrong
right
[root@localhost ~]# [[ "$A" == "$C" ]]&& echo right||echo wrong
wrong

文件測試

存在性測試

-e file:文件存在性測試,存在為真,否則為假

-a file:同-e

存在性及類別測試

-b file :是否存在且為塊設備文件

-c file :是否存在且為字符設備文件

-d file :是否存在且為目錄文件

-f file :是否存在且為普通文件

-h file 或者-L file:存在且為符號鏈接文件

-p file :是否存在且為命名管道文件

-S file : 是否存在且為套接字文件

blob.png

文件權限測試:

-r file:是否存在且為可讀

-w file: 是否存在且為可寫

-x file: 是否存在且為可執行

文件特殊權限測試

-g file :是否存在且擁有sgid權限

-u file :是否存在且擁有suid權限

-k file :是否存在且擁有sticky權限

blob.png

文件大小測試

-s file :是否存在且為非空

blob.png

文件是否打開

-t fd :fd表示文件描述是否已經打開且與某終端相關

-N file:文件自上一次被讀取之后是否被修改過

-O file:當前有效用戶是否為文件屬組

-G file: 當前有效用戶是否為文件屬組

雙目測試

file1 -ef file2 :file1與file2是否指向同一個設備上的相同inode

file1 -nt file2: file1 是否新于file;

file1 -ot file2: file1 是否舊于file; ;

blob.png

組合測試條件

第一種:

    command1$$command2 并且

    command1||command2 或者

    !command 非

    例如[[ -e file ]] &&[[ -r file  ]]

第二種:

    expression1  -a  expression2 并且

    expression1  -o  expression2 或者

    !expression

     必須使用測試命令進行

關于位置變量總結 

1.位置變量中$@和$*的區別

當$@和$*不使用“”包起來時效果一樣

blob.png

blob.png

當$@和$*用“”包起來時,執行$@正常運行

但是執行$*時報錯顯示的是沒有“a b”這個文件后目錄,

說明使用“”時,$*是把所有參數當作一個字符串的

$@則是每個參數都是分開的

blob.png

blob.png

$@和$*換個順序看看有影響沒

blob.png

blob.png

結果一樣,所以上面結論成立

上課的時候老師好像不是這樣驗證的,我嘗試下老師的方法

首先我創建了三個腳本,內容如下分別是t2.sh,t3.sh,t1.sh

其中t1.sh是t2.sh,t3.sh子腳本(后面簡稱腳本1.2.3)

blob.pngblob.pngblob.png

我們先看下運行三個腳本結果如何

運行腳本1時,1.2.4命令正常執行,說明命令和參數都沒有問題,從其結果看也是正確的

命令3執行時顯示的的是“a b c”這個文件,這是把a b c當作的是一個參數,和上面的結論一樣的

這樣說明了$*是把多個參數當作一個字符串的

blob.png

運行腳本3時,命令1.2正常執行,且結果正確,然后執行子腳本t1.sh參數是$*

但是t1第一行顯示的a b c,t2第二行命令沒顯示,說明第二行沒參數,所以沒顯示

t1第三四行顯示正常結果,再次證明t1.sh運行時只有一個參數“a b c”

blob.png

在運行腳本2

所有參數都是正常執行,

blob.png

在強調一下結論:

     在被雙引號包起來時 $*傳遞給腳本的所有參數,全部參數合為一個字符串,變成一個參數    

     $@不受影響,每個參數依然是獨立的

$#:傳遞到腳本的參數個數

$0:命令本身

$$:腳本運行的當前進程ID號

$!:后臺運行的最后一個進程的進程ID號

$?:顯示最后命令的退出狀態結果

    0:成功    

    1-255:失敗

練習


1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。

腳本內容如下:

1 #!/bin/bash
  2 #The current host system information
  3 echo -e "hello,everyone, \nThe current host system information is as follows"
  4 echo -e " "
  5 echo "hostname :`hostname`"
  6 echo ""
  7 echo "ip:`ifconfig |head -n2|tail -n1|tr " " ":"|tr -s ":"|cut -d: -f3`"
  8 echo ""
  9 echo -e  "system version:`cat /proc/version`"
 10 echo ""
 11 echo "kenel version:`uname -r`"
 12 echo ""
 13 echo -e "CPU Model:`lscpu |grep "Model name"|cut -d: -f2|sed 's@^[[:space:]]\+@@'`"
 14 echo ""
 15 echo -e "the memory capacity :`free -h|tr " " ":"|tr -s ":"|head -2|tail -1|cut -d: -f2`"
 16 echo ""
 17 echo -e "hard drive size:`fdisk -l |head -2|tail -1|cut -d: -f2|cut -d, -f1`"

運行結果如下:

blob.png

2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中

腳本內容如下

 1 #!/bin/bash
 2 #discription:wen jian bei fen
 3 cp -a  /etc/  /root/etc`date +%Y-%m-%d`

因為暫時還沒學到每日實現,只能做到手動備份,結果如下

blob.png

3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值

指令如下

 1 #!/bin/bash
  2 #ci pan li yong lv
  3 df|grep "sda"|tr " " ":"|tr -s ":"|cut -d: -f5|sort -rn|head -n1|tr -d "%"

結果:

blob.png

4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序

命令如下

1 #!/bin/bash
  2 netstat -nt|grep tcp|tr " " ":"|tr -s ":"|cut -d: -f6|sort |uniq -c|sort -rn

blob.png

5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和

命令如下:

 1 #!/bin/bash
  2 user1_id=`cat /etc/passwd |head -10|tail -1|cut -d: -f3`
  3 echo "the 10 user_id: $user1_id"
  4 user2_id=`cat /etc/passwd |head -20|tail -1|cut -d: -f3`
  5 echo "the 20 user_id: $user2_id"
  6 sumid=$[$user1_id+$user2_id]
  7 echo "the sumid:$sumid"

結果:

blob.png

6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和

空行和空白行表示的應該是不一樣的

空行:^$

空白行:^[[:space:]]*$space

指令1如下

 1 #!/bin/bash
  2 num1=`cat /etc/rc.d/init.d/functions |grep "^[[:space:]]*$"|wc -l`
  3 echo "the 1st is: $num1"
  4 num2=`cat /etc/fstab |grep "^[[:space:]]*$"|wc -l`
  5 echo "the 2st is: $num2"
  6 sumspace=$[$num1+$num2]
  7 echo "the sum is: $sumspace"

blob.png

指令2如下

  1 #!/bin/bash
  2 num1=`cat /etc/rc.d/init.d/functions |grep "^$"|wc -l`
  3 echo "the 1st is: $num1"
  4 num2=`cat /etc/fstab |grep "^$"|wc -l`
  5 echo "the 2st is: $num2"
  6 sumspace=$[$num1+$num2]
  7 echo "the sum is: $sumspace"

blob.png

7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件

命令:

  1 #!/bin/bash
  2 num1=`ls -A /etc|wc -l`
  3 echo "etc: $num1"
  4 num2=`ls -A /var|wc -l`
  5 echo  "var: $num2"
  6 num3=`ls -A /usr|wc -l`
  7 echo  "usr :$num3"
  8 sumfile=$[$num1+$num2+$num3]
  9 echo "the sumfile: $sumfile"

blob.png

8、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數

命令:

1 #!/bin/bash
2 num1=1
3 [[ $# -lt  $num1  ]]  &&( echo "zhishaoyinggai geiyige canshu" ;exit)|| grep "^$" $1|wc -l

blob.png

9、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫

命令

 1 #!/bin/bash
  2 [ -r /tmp/file1  -o  -w /tmp/file1 ]&&echo 讀寫至少一個 ||echo 不可讀且不可寫

blob.png

10、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。

說明下,當/etc/nologin文件存在時,用戶是禁止登錄的,知道了這個上面的就簡單了

禁止登錄

 1 #!/bin/bash
 2 [ -f /etc/nologin ] && echo "user cannot login" || (touch /etc/nologin; echo "user cannot login")

blob.png

允許登錄

 1 #!/bin/bash
 2 [ -f /etc/nologin ]&& (rm -rf /etc/nologin ; echo "user can login") ||echo  "user already login"

blob.png

11、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法并退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”

命令:

1 #!/bin/bash
2 ping -c1 -w1 $1 &>/dev/null &&echo "the ip can access" ||echo "the ip cannot access"

blob.png

12、計算1+2+3+…+100的值

1 #!/bin/bash
  2 echo the sumnumis: `echo {1..100}|tr " " "+"|bc`

blob.png

13、計算從腳本第一參數A開始,到第二個參數B的所有數字的總和,判斷B是否大于A,否提示錯誤并退出,是則計算之

1 #!/bin/bash
 2 [[ $1 -lt $2  ]] && seq -s+ $1 $2|bc || (echo "error" ;exit)

blob.png

原創文章,作者:qiuwei,如若轉載,請注明出處:http://www.www58058.com/33529

(0)
qiuweiqiuwei
上一篇 2016-08-15
下一篇 2016-08-15

相關推薦

  • LINUX下的RPM應用

    一 前言 在進入RPM的應用前,關于可執行程序的一些基本知識有必要說明一下: 1 ABI:application binary interface,這是應用程序與系統間的協議,大家都知道同一個程序在不同的操作系統平臺可能會無法執行,很大程度上就是因為ABI的不同,因此,對于可執行程序,選擇對應操作系統平臺是第一步 2 API:application prog…

    Linux干貨 2017-04-17
  • 姍姍來遲的第四周作業

    1、復制/etc/skel目錄為/home/tuser1,要求/home/tuser1及其內部文件的屬組和其它用戶均沒有任何訪問權限。     [root@www /]# cp -r /etc/skel /home/tuser1 &&&nbsp…

    Linux干貨 2016-11-30
  • sed與vim

    sed工具 簡介 ?Stream EDitor, 行編輯器 ?sed是一種流編輯器,它一次處理一行內容。處理時,把當前處理的行存儲在臨時緩沖區中,稱為“模式空間”(pattern space),接著用sed命令處理緩沖區中的內容,處理完成后,把緩沖區的內容送往屏幕。接著處理下一行,這樣不斷重復,直到文件末尾。文件內容并沒有改變,除非你使用重定向存儲輸出。Se…

    Linux干貨 2016-08-15
  • 文本處理工具

    一、文本處理工具的分類:     查看全部內容:more、less、cat、tac、rev     截取文件內容:head 、tail     抽取文件內容:cut     抽取關鍵字:grep、eg…

    Linux干貨 2016-08-08
  • 新的開始

    加入馬幫,新的開始,加油!

    Linux干貨 2016-09-19
  • 【N25第一周作業】Linux上命令的使用格式和基礎命令詳解

    一、Linux上命令的使用格式 命令行提示符詳解: 用戶通過終端的命令行接口來控制操作系統,登陸后如下: [root@localhost ~]# root: 當前登錄的用戶 @:分隔符 localhost: 當前主機的主機名,非完整格式;此處的完整格式為:localhost.localdomain [root@localhost ~]#&…

    Linux干貨 2016-12-03

評論列表(1條)

  • 馬哥教育
    馬哥教育 2016-08-16 14:18

    總結的很好很詳細,態度認真,內容充實,排版精美,再接再厲。

欧美性久久久久