shell基礎知識總結

1. shell

  對於一臺計算機而言,其硬件受系統內核的控制,使用者想要控制計算機,就必須有與系統內核進行通信的手段。而shell就是使用者與計算機進行通信的手段之一。從命名上看,shell實際上是相對於kernel(內核)而言,指系統與外界(使用者)進行接觸的部分,一個提供系統功能給用戶使用的軟件,它接受來自用戶的指令,而後調用相應的應用程序。
  爲了知足不一樣的需求,shell提供了兩種執行命令方式:linux

  • a. 交互式:解釋並執行用戶輸入的命令或者自動地解釋和執行預先設定好的一連串的命令。
  • b. 程序設計式:做爲一種腳本語言,提供變量、控制結構和函數,再經過解釋器解釋並執行。
    Linux上常見的shell有sh、bash、ksh、tcsh等,不一樣解釋器在某些語法的執行方面可能有些不一樣。經過查看/etc/shells文件就能夠知道本系統所支持的shell解釋器類型。如shells的文件內容以下:
    ryeshen@~$ cat /etc/shells
    /bin/sh
    /bin/bash
    /sbin/nologin
    /usr/bin/sh
    /usr/bin/bash
    /usr/sbin/nologin
    /bin/tcsh
    /bin/csh
    /bin/ksh
    /bin/zsh
      而linux默認是用的解釋器是bash。在腳本頭能夠聲明本腳本所使用的解釋器,
    聲明方式: #!/bin/bash

2. 變量

  • a. 賦值

    • 賦值方式:variable_name = variable_value
    • 等號兩邊不能有空格符;
    • 增長變量內容:PATH=」$PATH」:/home/bin
    • 取消變量:unset variable_name
    • 變量類型:可使用declare [[-/+]aixr] [name[=value] …],其中-表示賦予變量屬性,+表示去除變量屬性,a-數組,i-整數,r-只讀,x-環境變量
  • b. 自定義變量與環境變量

    • 使用「=」賦值獲得的自定義變量,這個變量的做用域爲當前shell進程。
    • 使用export命令能夠聲明一個環境變量,一個環境變量的做用域爲當前shell進程及
      其shell子進程(subshell)。
    • 在啓動shell進程的時候,shell會從文件中加載一些默認的環境變量到shell進程中,
      如HOME、PATH等。
    • 用env能夠查看當前全部的環境變量,set則能夠看全部的環境變量和自定義變量。
    • p.s. 關於子shell進程

      • i. 建立一個shell子進程的方式包括但不限於:
        • 使用&提交後臺做業。後臺做業於subshell中運行;
        • 使用管道。|左右的命令均在獨立的subshell中運行;
        • 括號操做符。()中的命令在subshell中運行;
        • 執行外部腳本或程序。
      • ii. subshell能夠繼承shell父進程的屬性包括:當前的工做目錄、環境變量、標準輸入輸出和錯誤輸出、全部已打開的文件描述符、忽略的信號。
      • iii. subshell對環境變量的修改對shell父進程不可見。
  • c. shell中的單引號、雙引號和反引號

    • 雙引號:保留$的變量擴展功能,使用變量時會$後的變量轉變爲變量的值。在雙引號中可使用轉義符\將$轉變爲純文本符號。使用雙引號後不支持正則匹配。
    • 單引號:不保留特殊符號的功能,括號內內容僅做爲純文本進行使用。
      如:正則表達式

      ryeshen@~$ echo "I am $name"
      I am someone
      ryeshen@~$ echo 'I am $name'
      I am $name
    • 反引號:引號內內容會被做爲命令先被執行,命令的結果做爲引號的輸出。$()的效果與之相同
      如:shell

      ryeshen@~$ echo I am `pwd`
      I am /home/asl
      ryeshen@~$ echo I am $(pwd)
      I am /home/asl
    • p.s. 反引號與$()的一點區別

        — 參考自http://km.oa.com/articles/show/310289
      先來看幾個例子:
      ryeshen@~$ echo `echo \$SHELL`
      /bin/bash
      ryeshen@~$ echo $(echo \$SHELL)
      $SHELL
      ryeshen@~$ echo `echo \\$SHELL`
      $SHELL
      ryeshen@~$ echo $(echo \\$SHELL)
      \/bin/bash
      ryeshen@~$ echo `echo \` 
      > 
      ryeshen@~$ echo $(echo \\)
      \
        參考的文章的解釋是「反引號齊自己就對\進行了轉義,保留了齊自己意思,若是咱們想在反引號中起到\的特殊意義,咱們必須使用2個\來進行表示」。
        對此個人理解是,在反引號中,\表示續行(見倒數第二個例子),\才表示轉義符。而在$()中,\自己就起到轉義符的效果。

      3. 數組

  • a. 賦值

    #shell腳本中#表示行註釋
      array=(0 1 2 3 4)
      array[101]=101           #直接經過 數組名[下標] 就能夠對其進行引用賦值。
                                         #若是下標不存在,自動添加新一個數組元素
      unset array[101]         #使用unset清除指定值
      unset array              #使用unset清除整個數組
  • b. 取值

    echo ${array[2]}      #使用下標獲取值   
    echo ${a[@]}         #使用@或*獲取數組全部值
    echo ${a[*]}

    輸出結果:數組

    2
    0 1 2 3 4
    0 1 2 3 4
  • c. 截取

    #${數組名[@或*]:起始位置:長度}
    newArray=(${array[@]:1:3}) #先截取數組"1 2 3",再將截取到的數組賦給newArray
  • d. 遍歷

    for a in ${arr[@]} 
    do    
         echo "$a" 
    done
  • e. 拆分字符串到數組

    a="one,two,three,four"
    OLD_IFS="$IFS"    #使用臨時變量保存環境變量IFS的值
    IFS=","                    #給環境變量IFS賦值,這個值用來切割字符串 
    arr=($a)                  #字符串切分 
    IFS="$OLD_IFS"    #還原IFS

4. 語法

  • a. if

    if語句的格式以下:
    if …; then  
      …
    elif …; then   
      … 
    else    
      … 
    fi
    注意格式中分號;的使用。
    if的判斷語句中,方括號和邏輯運算符兩邊都必須有空格(「]」的右邊除外)。
  • p.s. []必須有空格的緣由

      「[「 是linux系統中的指(試試whereis [),用法與test相同,但最後一個參數必須是 「]」。這也是爲何then前面要加分號」;」的緣由。類似地能夠推出,if後面能夠接其餘指令,利用其返回值進行判斷,當返回值爲0時if才判斷爲true
    如:
    ryeshen@~$ if echo "123"; then
    > echo "123"
    > fi
    123
    123
  • p.s. (),(()),[]和[[]]

    ( ): 1. 用於數組的初始化
      2. 指令羣組(command group),即用括號將一組命令包括起
    來,這組命令共用一個shell子進程,所以能夠分享自定義變量等。
    (( )): 至關於命令let,用於算數運算。舉個例子:bash

    ryeshen@~$ ((a=1+1)); echo $a
    2
    ryeshen@~$ ((a=1+1)); echo $a
    2

    [ ]和[[ ]]的區別:
     如上所說,[實際上是一個指令,所以使用判斷中字符串時最好用雙引號括住,
    且>、<必須改寫成>和\<(>,<是重定向符)。
      另外,在使用&&和||時,必須寫成 [ cond1 ] && [ cond2 ] 的形式。
    [[ ]]則是bash的關鍵字。能夠直接使用>、<、&&、||,如[[ a>1 && b>2 ]]。
     [[ ]]中字符串未雙引號括住的話,能進行正則表達式匹配。如:函數

    ryeshen@~$ [[ ab == a* ]] && echo "ok"
    ok

    if語句支持的運算符/操做符:(能夠理解爲是[指令的參數,就像rm -rf同樣)

    學習

  • b. for

    for var in …; do
          do something
    done
    for (( cond1; cond2; cond3 )) do
          do something
    done

應用示例:ui

#輸出1 2 3 4 …… 10
for i in $(seq 10); do    #這裏是用seq指令生成了"1 2 3 …… 10"的字符串
        echo $i;
done;
    #判斷輸入的字符串是否是文件名
for file in $*; do    # $*指從命令行讀入的參數,如輸入"test.sh a.xml b.txt c.pdf",則$*=(a.xml b.txt c.pdf)
        if [ -f "$file" ]; then
            echo "INFO: $file exists"
        else
            echo "ERROR: $file not exists"
        fi
done;
  • p.s. 關於腳本的傳入參數

    • $#是入參的個數,
    • $@和$*是當前全部的入參
    • $0是腳本的名字
    • $1是第一個入參,$2是第二個入參,以此類推
    • pp.s. $@和$*的區別
      • 不被雙引號」」括起來時,$@和$*一致。
      • 被雙引號」」括起來時:
        • 「$*」表示「$0IFS$1IFS$2」。舉個例子,設IFS爲「-」,入參爲「1 2 3」,則輸出爲「1-2-3」。
        • 「$@」與$@相同
          ```
  • c. while和until

    while [ cond1 ] && { || } [ cond2 ] …; do
          do something
    done
    until [ cond1 ] && { || } [ cond2 ] …; do
          do somethingdone
    應用示例:
    # 逐行輸出/etc/hosts文件內容
    while read line; do
          echo $line;
    done < /etc/hosts;
    # 這裏能讀入/etc/hosts,是由於<將文件重定向到read指令
  • d. case

    case var in
      pattern 1 )
          … ;;
      pattern 2 )
          … ;;
      *)
          … ;;
    esac
  • case行尾必須爲單詞「in」,每個模式必須以右括號「)」結束。
  • ;; 表示命令序列結束。
  • pattern可使用匹配符,如
    • a|b: a或者b
    • *:匹配任意長度的任意字符;
    • ?:匹配任意單個字符;
    • [-]:範圍匹配
  • 另外提一下shfit,它能夠將入參左移,即進行賦值:$1=$2;$2=$3;$3=$4……
    case能夠與shfit結合使用,用於根據入參進行處理,舉例以下:
    shell腳本test.sh:spa

    #!/bin/bash
    while [ $# -gt 0 ]; do
          case $1 in
          -a)
                  shift; echo a-$1; shift;
          ;;
          -b|-d)
                  shift; echo bd-$1; shift;
          ;;
          -c)
                  shift; echo c-$1; shift;
          ;;
          *)
                  echo unkown; shift;
          esac
    done

    輸出:命令行

    ryeshen@~$ ./test.sh -a 1 -c 2 -b 3 -d 3
    a-1
    c-2
    bd-3
    bd-3
  • e. function

    • 函數定義
      functionname()
      {
      do something
      }
      function func() 
      {
      do something
      }
    • 函數調用
      函數必須先定義後使用。
      func param1 param2 ... # 函數內使用$#,$1等方式獲取參數屬性和參數,與腳本獲取入參相似
  • 函數返回值
    func
    ret=$?            #使用$?獲取函數的執行結果
    ret=`func`      #使用反單引號執行函數並將返回值賦值給變量
  • 函數變量
    + 腳本中定義的變量可在函數中使用
      + 函數中可用local關鍵字聲明屬於本身的,不被外部可見的局部變量 

後記

  學習過shell的基礎知識後,最大的感覺是原覺得是 shell腳本的特殊用法事實上是有規律可推理的。在此以前,雖然知道[]兩邊要加空格、使用while read $line;do……done < a.txt能夠逐行讀入文件等零碎的知識點,但只是知其然殊不知其因此然。瞭解了shell的特殊符號的含義後,才發現這些東西並不是只能靠死記硬背,而是有規則可循的。

相關文章
相關標籤/搜索