shell腳本入門

一、基礎概念

編程語言有低級語言和高級語言兩類。
高級語言也有編譯型和解釋型的區分,編譯型語言有C,C++,jave;解釋型語言有shell,perl,python
shell腳本是一種包含聲明或命令,并符合一定格式的文本文件
shell作為一種過程式解釋型的編程語言,它的基本組織結構有:

數據存儲:變量、數組
表達式
語句:if while case

shell腳本的格式有:

#!SHEBANG    
CONFIGURATION_VARIABLES     
FUNCTION_DEFINITIONS    
MAIN_CODE

shell腳本格式要求首行必須是shebang機制 ,shebang也是指明文件調用的解釋器類型

#!/bin/bash     
#!/usr/bin/python    
#!/usr/bin/perl      
  • 創建shell腳本

第一步:使用文本編輯器來創建文本文件

第一行必須包括shell 聲明序列:#!    
    #!/bin/bash
添加注釋
    注釋以# 開頭

第二步運行腳本:

給予執行權限,通過具體的文件路徑指明文件執行。    
直接運行解釋器,將腳本作為解釋器程序的參數運行。
  • 腳本調試
檢測腳本中的語法錯誤
    bash -n /path/to/some_script
調試分布執行
    bash -x /path/to/some_script
  • 執行腳本

      /root/danran.sh    絕對路徑,可以作用于子進程
      .  /danran.sh   相對路徑,可以作用于子進程
      bash /root/danran.sh   可以作用于子進
      source /root/danran.sh   不會打開子進程,僅僅作用于當前進程 
    

二、變量: 命名的存儲空間

數據的存儲方式有:

字符:   
數值:整型,浮點型 

變量類型:
作用:

1、定義數據存儲格式
2、定義參與的運算    
3、表示的數據范圍

類型:

字符    
數值:整型,浮點數

編程語言的變量又有強類型和弱類型的區分

強類型:jave,C++
    變量不經過強制轉換,它永遠是這個數據類型,不允許隱式的類型轉換,故需要定義數據類型
弱類型:bash
   變量會有隱式轉換,故不需要指定數據類型,所有要存儲的數據都當做字符進行,不支持浮點數

邏輯運算

與: 
    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,第二個必須參與運算

三、bash中的變量的種類

根據變量的生效范圍為標準:

本地變量:生效范圍為當前shell進程,對當前shell之外的其他的shell進程無效,包括當前shell的子shell進程均無效;    
環境變量:生效范圍為當前shell進程及其子進程;    
局部變量:生效范圍為當前shell進程中某代碼片段(通常指函數);  
位置變量:$1,$2,...來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數;    
特殊變量:$?,$0,$*,$@,$#,$$    

本地變量:

變量賦值:name=“value”
    可以使用單引號:
        value:
            (1)可以是直接賦值:name=“filename”
            (2)變量引用:name=“$username”
            (3)命令引用:name=`COMMAND`,name=$(COMMAND)
變量引用:$(name),$name
    "":弱引用,其中的變量引用會被替換為變量值;
    '':強引用,其中的變量引用不會被替換為變量值,而保持原字符串;
顯示已定義的所有變量:
    set
撤銷變量:
    unset name

環境變量:

變量聲明、賦值
    export name=VALUE
    declare -x name=VALUE
變量引用:$name,$(name)
顯示所有環境變量:
    export
    env
    printenv
    declear -x
撤銷變量:
    unset name
bash中有很多內置的環境變量,PATH,SHELL,UID,HISTSIZE,PWD,OLD,HISTFILE,PS1,_
_:上一個命令的最后一個字符串
  • 變量命名法則:

    1、不能使用程序中的保留字,如if、for
    2、只能使用數字、字母及下劃線,且不能以數字開頭
    3、最好見名知義

只讀變量:

設置只讀變量:
    readonly name
    declare -r name 
查看只讀變量:
    readonly -p 

位置變量:

在腳本代碼中調用通過命令行傳遞給腳本的參數:
    $1,$2,....:對應調用第1,第2....個參數,$10以上的應使用括號${10} ,${12}  
        shift [n] 調換位置,n不能大于參數的個數
    $0:調用命名本身
    $*:傳遞給腳本的所有參數,將所有參數作為一個整體字符傳遞
    $@:傳遞給腳本的所有參數,每一個參數獨立傳遞,與$*只有在使用“”引起來時才有區別
    $#:傳遞給腳本的參數個數   
    set --:清空所有位置變量參數
    
特殊變量:$?,$0,$*,$@,$#,$$
    $?:返回狀態碼
    $$:返回當前進程的進程編號

image
image



四、bash的配置文件

按生效范圍劃分:存在兩類
    全局配置:
        /etc/profile
            /etc/profile.d/*.sh
        /etc/bashrc    
    個人配置:
        ~/.bash_profile
        ~/.bashrc
按功能劃分:存在兩類
    profile類:為交互式登錄的shell提供配置
        全局:/etc/profile,/etc/profile.d/*.sh
        個人:~/.bash_profile
        功用:
            (1)用于定義環境變量
            (2)運行命令和腳本
   
    bashrc類:為非交互式登錄的shell提供配置
        全局:/etc/bashrc
        個人:~/.bashrc
        功用:
            (1)定義命令別名
            (2)定義本地變量
    修改文件后生效:
       1、重啟shell進程
       2、source ~/.bashrc
          . ~/.bashrc  
bash退出任務
    保存在~/.bash_logout 文件中(用戶)
    在退出登錄shell 時運行
    用于
        創建自動備份
        清除臨時文件

shell登錄:
    交互式登錄:
        直接通過終端輸入賬號密碼;
        使用“su -UserName”或“su -l UserName”切換的用戶
        讀取文件的順序:
            /etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
    非交互式登錄:
        su UserName
        圖形界面下打開終端
        執行腳本
        文件讀取順序:
            ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh 
編輯配置文件定義的新配置的生效方式:
    (1)重新啟動shell進程
    (2)使用source或.命令進程   

五、bash中進行算數運算

+,-,*,/,%,...
實現算數運算:
    (1)let var=算數表達式
        sum1=3;sum2=4;let sum=$sum1+sum2
    (2)var=$(算術表達式)
    (3)var=$((算術表達式))
    (4)var=$(expr arg1 arg2 arg3...) expr命令,參數之間用空格隔開 
        sum=$(expr $num1 \* $num2)
            *在某些場景下需要轉義
    (5)declare -i var = 數值
    (6)echo '算術表達式' | bc
            
bash有內置的隨機數生成器:$RANDOM
    echo $[$RANDOM%60]  對60取模,即生成0-59之間的某個數
    echo $[$RANDOM%60+1]   取1-60之間的某數
增強型賦值:
    +=,-=,*=,/=,%=
    count+=1  <==> count=count+1
自增,自減:
    let var+=1 <==> let var++
    let var-=1 <==> let var--
練習:  

1、編寫腳本sumid.sh,計算/etc/passwd文件中的第10個用戶和第20個用戶的id之和
    #! /bin/bash
    user10="`head -n $2 $1 | tail -n 1|cut -d: -f3`"
    user20="`head -n $3 $1 | tail -n 1|cut -d: -f3`"
    let sum=$user10+$user20
    echo "user id sum is $sum"
2、編寫腳本/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和  

    #!/bin/bash
    spaceline1=`grep "^[[:space:]]*$" $1 | wc -l`
    spaceline2=`grep "^[[:space:]]*$" $2 | wc -l`
    echo "The sum of space line:$[spaceline1+spaceline2]"
3、生成腳本模板
    #!/bin/bash
    [ $# -gt 1 ] &&{ echo "the args is error";exit;}
    [ $# == 0 ] && read -s -p "please input script name: " name || name="$1"
    echo "#!/bin/bash
    # filename "$name"
    # author:danran 
    # time is `date +%F`" >"$name"
    chmod +x "$name"
    vim "$name"

4、編寫腳本,統計/etc、/usr、/var目錄中有多少個一級子目錄和文件
    #!/bin/bash
    # danran
    # time is Mon Jun  5 13:09:12 CST 2017
    line1=`ls $1 | wc -l`
    line2=`ls $2 | wc -l`
    line3=`ls $3 | wc -l`
    let sum=$line1+$line2+$line3
    echo $sum

六、條件測試

判斷某需求是否滿足,需要由測試機制來完成;
Nnote:專用的測試表達式需要由測試命令輔助完成測試過程;
評估布爾聲明,以便用在條件性執行中
    若真,則返回0
    若假,則返回1
測試命令:
    [:內部命令
    [[:shell關鍵字
測試命令:
    test EXPRESSION
    [ EXPRESSION ]
    [[ EXPRESSION ]]
    Note:EXPRESSION前后必須有空白字符
bash的測試類型:
    數值測試
        -gt:大于
        -ge:大于等于
        -eq:等于
        -ne:不等于
        -lt:小于
        -le:小于等于
    字符串測試
        ==/=:等于
        >:大于
        <:小于
        !=:不等于
        ~=:左側字符是否能被右側的PATTERN所匹配
            Note:一般用于[[ ]]中
        -z “STRING” 測試字符串是否為空,空為真,不空為假
        -n “STRING” 測試字符串是否不空,不空為真,空為假  
        eg  [ -z "$name" ]
            [[ $name ~= ^a ]]  匹配$name是否a開頭
        -v VAR 檢查變量VAR是否設置
            eg:[ -v var ]   
        Note:用于字符串比較時的用到的操作數都應使用引號   
    文件測試
        存在性測試:
            -a:FILE   同-e
            -e:FILE:文件存在性測試,存在為真
        存在性及類別測試:
            -b FILE:是否存在且為塊設備文件
            -c FILE:是否存在且為字符設備文件
            -d FILE:是否存在且為目錄文件
            -f FILE:是否存在且為普通文件
            -S FILE:存在且為套接字文件
            -L FILE 或 -h FILE:存在且為鏈接文件
            -p FILE:是否存在且為命名管道文件  

先判斷文件是否為鏈接文件,在判斷文件的類型,因為測試鏈接文件時是檢測鏈接原文件,故應先判斷是否為鏈接文件

        文件權限測試:(當前用戶)判斷文件權限時,首先判斷文件是否存在
            -r:文件是否存在且可讀
            -w:文件是否存在且可寫
            -x:文件是否存在且可執行
        文件特殊權限測試:
            -g FILE:文件存在且擁有guid權限,suid對腳本無效,腳本不是二進制文件
            -u FILE:文件存在且擁有suid權限
            -k FILE:是否存在且擁有sticky權限
        文件大小測試:
            -s FILE:文件是否存在且非空
        文件打開性測試:
            -t fd:fd表示文件描述符是否已經打開且與某終端相關
            -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               非
        第二種方式:
            [ EXPRESSION1 -a EXPRESSION2 ]   與
            [ EXPRESSION1 -o EXPRESSION2 ]   或
            !EXPRESSION                     非
            必須使用測試命令進行
        [ -f /bin/cat -a -x /bin/cat ] && echo "true"
        [ ! -r /app/a -a ! -w /app/a ] && echo true <==> [ ! \( -r /app/a -o -w /app/a \) ] && echo "true"
練習:
    1、編寫腳本/root/bin/excute.sh,判斷參數文件是否為sh后綴的普通文件,如果是,添加所有人可執行權限否則提示用戶非腳本文件
        #!/bin/bash
        [ $# == 0 ] && read -p "please input fimename" name || name=$1
        [ -f $name ] && [[ "$name" =~ \.sh$ ]] && chmod a+x $name || echo "$name not scripts file"     
    2、編寫腳本/bin/per.sh,判斷當前用戶對指定的參數文件,是否不可讀并且不可寫
        #!/bin/bash
        [ ! -r $1 -a ! -w $1 ] && echo "$1 file not read and not write"
    3、編寫腳本/root/bin/checkdisk.sh,檢查磁盤分區空間和inode使用率,如果超過80%,就發廣播警告空間將滿
        #!/bin/bash
        inode=`df -i | grep "^/dev/sd*" | tr -s ' ' '%'| cut -d'%' -f5| sort -r | head -n 1`
        disk=`df | grep "^/dev/sd*" | tr -s ' ' '%'| cut -d'%' -f5| sort -r | head -n 1`
        [ $inode -gt 80 ] && echo "danran"
        [ $disk -gt 80 ] && echo "dan"

七、bash自定義退出狀態碼

exit [n]:自定義退出狀態碼為n
    Note:腳本中一旦遇到exit命令,腳本會立即終止,終止退出狀態取決于exit命令后面的數字n。
Note:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決于腳本中執行最后一條命令的狀態碼。
進程使用退出狀態來報告成功或失敗
     0 代表成功,1 -255 代表失敗
    $?  變量保存最近的命令退出狀態

練習:編寫腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;
    如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;
    如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
        #!/bin/bash
        [ $# -lt 1 ] && (echo "please input a arge" && exit ) || echo "`grep "^$" $1  | wc -l`"

八、read

使用read 來把輸入值分配給一個或多個shell 變量

-p 指定要顯示的提示 
    eg:read -p "danran" file 
-s 靜默輸入,一般用于密碼
-n N  指定輸入的字符長度N
-d ‘ 字符’ 輸入結束符
-t N  TIMEOUT 為N秒,當等待時機超過N秒時自動退出

read 從標準輸入中讀取值,給每個單詞分配一個變量,所有剩余單詞都被分配給最后一個變量,多個字符使用重定向賦值多個變量時,使用>>>三個重定向方可


  • bash如何展開命令行

把命令行分成單個命令詞
展開別名
展開大括號的聲明({})
展開波浪符聲明(~)
命令替換$() 和 ``)
再次把命令行分成命令詞
展開文件通配(* 、? 、[abc] 等等)
準備I/0 重導向(< 、>)
運行命令

防止擴展:

反斜線(\ )會使隨后的字符按原意解釋

加引號來防止擴展

? 單引號(’ )防止所有擴展
? 雙引號(” )也防止所有擴展,但是以下情況例外:

$ (美元符號) - 變量擴展
` (反引號) - 命令替換
\ (反斜線) - 禁止單個字符擴展
! (嘆號) - 歷史命令替換
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容

  • 一、基礎知識 編程語言有低級語言和高級語言兩類。高級語言也有編譯型和解釋型的區分,編譯型語言有C,C++,jave...
    JevonWei閱讀 324評論 0 0
  • Ubuntu的發音 Ubuntu,源于非洲祖魯人和科薩人的語言,發作 oo-boon-too 的音。了解發音是有意...
    螢火蟲de夢閱讀 99,449評論 9 467
  • 社會是每個人都要經歷的一所大學。而對于剛從高校畢業的學生,從這所大學到社會這所“大學”,其中的轉折并不都是...
    willwilling閱讀 259評論 0 0
  • 夜色如夢 繁星滿天 天邊一顆流星劃過 那是我 劃過就是劃過 夜色如夢 繁星滿天 平靜的湖面如鏡 投入一粒石子 那是...
    隨君到夜郎閱讀 283評論 0 1
  • 有獎征文,,征圖 一,e貨的故事 二,e 貨是什么? 三,我心中的e貨 等等內容,形式不限,可以故事,可以詩歌,可...
    西山e貨閱讀 161評論 0 0