天天看點

bash shell 臨時筆記

1. 1變量替換

1. 2參數替換

1.1.1 變量的名字是它的值儲存的地方。引用它的值稱為變量替換(variable substitution)。.

              如 果variable1是一個變量的名字,那麼$variable1就是引用這個變量的值

              變量指派: var_name="var_value"     等号兩邊不能有空格 ;給變量賦的值中有空白字元,“ ”引号是必須的

                                read var_name

                                for  var_name in num1 num 2

                                var_name=$(cmd)   指令替換,注意要保持指令行輸出的完整性,最好var_name="$(cmd)" ,使用雙引号

             變量替換: $var_name 等同于 ${var_name}   在某些場合使用$variable形式會引起錯誤,這時你可能需要使用${variable}的形式了

                                "$var_name"       在一個雙引号(" ")裡的變量引用不會禁止變量替換。是以雙引号被稱為部分引用,有時也稱為"弱引用"

                               變量替換不能用‘$var_name’     一個單引号裡(' ')的變量替換是被禁止的,變量名隻被解釋為普通的字面意思

1.1.2  一個未初始化的變量有一個”null”值――表示從沒有被指派過(注意null值不等于零)。雖然有時在數學運算會被當成0 ,但是不可靠,但是該行為無法預期 。

1.1.3 變量沒有類型。

         本質上來說,Bash變量是字元串,但是根據環境的不同,Bash允許變量有整數計算和比較。其中的決定因素是變量的值是不是隻含有數字

1.1.4特殊變量種類

        局部變量     local loc_var=23       # 聲明為局部變量

        環境變量

             1.1.4.1

               每次一個Shell啟動時,它都會建立新的合适的環境變量。如果它增加或是更新一個環境變量,都會使這個Shell的環境表得到更新(譯者注:換句話說,更改或增加

               的變量會立即生效),并且這個Shell所有的子程序(即它執行的指令)能繼承它的環境變量。(譯者注:準确地說,應該是後繼生成的子程序才會繼承Shell的新環

               境量,已經運作的子程序并不會得到它的新環境變量)。

             1.1.4.2

              如果一個腳本要設定一個環境變量,則需要将它導出(”export”),也就是說要通知到腳本的環境表。這就是export指令的功能。這樣子腳本才會看到這個新修改變量

              一個腳本隻能導出(export)變量到子程序,也就是說隻能導出到由此腳本生成的指令或程序中。在一個指令行中運作的腳本不能導出一個變量影響到指令行的環境。

              子程序不能導出變量到生成它的父程序中

       位置參數

               注意$0

                     shift  ;

                     $* [email protected] ; $* 和[email protected] 結合不同的IFS,代表的東西可能不一樣

2.1.1設定變量的屬性 r x i

           declare或typeset内建指令(它們是完全相同的)可以用來限定變量的屬性.

           declare [+/-][rxi][變量名稱=設定值]或 declare-f

          參數說明:

                +/-  "-"可用來指定變量的屬性,"+"則是取消變量所設的屬性。

                -f  僅顯示函數。

                 r  将變量設定為隻讀。

                 x  指定的變量會成為環境變量,可供shell以外的程式來使用。

                 i  [設定值]可以是數值,字元串或運算式。

                 使用内建的declare可以來限定變量的範圍, foo (){    declare FOO="bar"    }   局部變量

2.1.2 變量的間接引用

         變量間接引用的實際用處是什麼? 它提供了Bash具有C中一點指針的功能 .

         Bash不支援指針運算,這極大地限制了間接引用的用處。事實上,在腳本語言裡間接引用是一個蹩腳地東西

        a=letter_of_alphabet   # 變量"a"儲存着另外一個變量的名字.    letter_of_alphabet=z

         # 間接引用.   eval a=\$$a

2.1.3 間接引用用到的指令字 eval

        eval的作用是再次執行指令行處理,也就是說,對一個指令行,執行兩次指令行處理

        2.1.3.1與eval一起記憶的一個指令let

             let 指令是 BASH 中用于計算的工具,用于執行一個或多個表達式,變量計算中不需要加上 $ 來表示變量。如果表達式中包含了空格或其他特殊字元,則必須引起來。

             shell程式中的操作預設都是字元串操作,在要運作數學運算符的時候可能得到意想不到的答案,是以用let

        2.1.3.2 與let一起的算術運算

               let不允許隻出現等号右邊的計算,用“ ”或者表達式中間沒有空格,不需要$ 。let ″j=i*6+2″等價于((j=i*6+2)),

               var=`expr$var+1`   将需要運算的表達式寫入在expr 後面,參數與運算符号中間有空格隔開 

              (())、expr 可以隻有等号右邊的計算,由$((...))、$(expr ...)、`expr ...` 檢視傳回結果                      expr表達式參數間必須有空格

     let和(())運作是内建指令,使用相同的算法。       let或者表達式用“”,或者表達式中間沒有空格

              let 和 expr 的運算是整數運算,不包括浮點預算

2.1.4 變量的檢查和初始化指派

         ${parameter-default}, ${parameter:-default}

                   前者變量沒有被聲明(變量的值是NULL,也看做被聲明),就使用這個default作為預設值;

                   後者變量沒有被設定(變量的值是NULL,也是沒有被設定),就使用default預設值

         ${parameter=default}, ${parameter:=default}  等同于上面

    ${parameter?err_msg}, ${parameter:?err_msg} 變量沒有被聲明或者被設定,列印err資訊

    ${parameter+alt_value},${parameter:+alt_value}

   如果變量parameter被聲明或被設定,使用alt_value作為新值,否則使用空字元串

2.1.5 對變量的值就行修改

 注意: Pattern 可以使用正規表達式,但是Replacement不能使用正規表達式

    ${var#Pattern}, ${var##Pattern}

“删除”從$var前端 開始的最短 或 最長比對$Pattern的字元串.  必須是從頭第一個字母開始的比對,否則替換不了

    ${var%Pattern}, ${var%% Pattern}

”删除“從$var後端 開始的最短 或 最長比對$Pattern的字元串。 必須是結尾最後一個字母的比對。       記憶方法:鍵盤上三個鍵的位置緊挨着:#$%

    ${var/#Pattern/Replacement}

”替換“如果變量var的字首比對模式Pattern,則用Replacement代替比對模式的字元串.

    ${var/%Pattern/Replacement}

”替換“如果變量var的字尾比對模式Pattern,則用Replacement代替比對模式的字元串.

        注意: 這些pos 不能使用正規表達式------------------------------------

    ${var:pos} ${var:(-pos)} 

變量var被展開成從位移pos個字元往後的值.pos為負值,則從字元後面的倒數pos位置提取字元

    ${var:pos:len}

從變量var中展開成從位移pos的字元往後最長為len的字元串。

    ${var/Pattern/Replacement}

在變量var第一個比對Pattern的字元串用Replacement代替.     變量中間的字元,不一定是開頭或者結尾的字元

如果省略了Replacement ,則第一個比對Pattern的字元串會被删除.

    ${var//Pattern/Replacement}

全局替換Global replacement.所有在變量var中被Pattern比對到的都由Replacement代替.

  2.1.6 檢視定義的變量        ${!varprefix*}, ${[email protected]}

比對所有前面聲明過的變量,并且變量名以varprefix開頭.

    ${!name[@]}  ${!name[*]}

      如果name為一個數組變量,那麼結果是該數組的所有下标的清單。如果name不是數組,那麼,如果name為空,結果就為空,如果name不為空,結果就為0. 2.1.7 變量的長度     ${#var}

字元串長度(即變量$var的字元個數)。
對于數組來說,${#array}是數組的第一個元素的長度.${#array[*]}和${#array[@]}表示數組中元素的個數

${#*}和${#@} 表示位置參數的個數

2.1.8 對變量操作的總結

      # 表示求長度

      !表示求變量的名字

      # 表示開頭比對 ,擴充 /# /% ## %% //

      % 表示結尾比對

      / 表示求替換

      沒有/ 的都是删除操作

3.1 内部指令和内建指令 3.1.1  内建指令就是bash工具自帶的指令,大多和linux系統指令是一個名字。           設立内建指令的原因就是(1)内建指令不需要fork一個新的程序,可以執行的更快(2)内建指令可能會通路bash的核心。           常用的内建指令,有:       3.1.1.1 I/O類                     echo                     printf                     read      3.1.1.2 檔案類                     cd                     pwd                     pushd popd dirs  操作目錄棧       3.1.1.3 變量類                     let                     eval                     set  unset:set -r 受限shell restricted                     export                     declare typeset                     readonly                     getopts       3.1.1.4 腳本類                     .(source 指令)  , source是在主程序的環境下執行,. 是在程序的子程序下執行                    exit                    exec                    caller                    shopt       3.1.1.5 指令類                    true false                    type                    hash                    bind                    help        3.1.1.6 作業控制類                    作業不是程序                    jobs                    discown                    fg bg                    wait                    suspend                    logout                    times                    kill                    command                    builtin                    enable                    autload          3.1.1.7 比較類                    test                    [           3.1.1.8 函數類                    return           3.1.1.9 terminfo操作                   tput           3.1.1.10 資料類                   seq    3.2.1 子shell         子shell中的變量是局部變量,不能被父程序讀取。         程序在不同的子shell中可以串行地執行.這樣就允許把一個複雜的任務分成幾個小的子問題來同時地處理         在子shell中的目錄更改不會影響到父shell         子shell可用于為一組指令設定臨時的環境變量         用 "|"管道操作把I/O流重定向到子shell,例如 ls -al | (command)       3.2.1.1 外部指令調用會産生一個子shell

    3.2.1.2( 指令1; 指令2; 指令3; ... )

              嵌在圓括号裡的一列指令在一個子shell裡運作     3.2.1.3 在一個花括号内的代碼塊不會運作一個子shell.

              { command1; command2; command3; ... }

    3.2.1.4 指令替換将會調用一個subshell :var=$() ; var=`do_action`

    3.2.1.5 & ,送出背景作業

    3.2.1.6 管道

    3.2.1.7 . (source指令)或者file指令

    3.2.1.8 exec指令

    3.2.1.9 函數調用

3.2.2 受限shell

     #bin/bash -r   或者 set -r   shell運作在受限模式下

     這是一種安全政策, 目的是為了限制腳本使用者的權限 , 受限shell模式下如下操作不能執行:

           使用cd 指令更改工作目錄.

           更改 環境變量 $PATH, $SHELL, $BASH_ENV,或 $ENV 的值.            讀或更改shell環境選項變量 $SHELLOPTS的值.            輸出重定向.            絕對路徑.            調用 exec來把目前的受限shell替換成另外一個不同的程序.            腳本中許多其他無意中能破壞或搗亂的指令.            在腳本中企圖脫離受限shell模式的操作.

3.2.3 指令替換

          将一個指令的輸出指派給某一個變量 。

          var=`do_action`  允許嵌套的,但要用\轉義``

          var=$(do_action)  允許嵌套的

          指令替換甚至允許将整個檔案的内容放到變量中, 可以使用重定向或者cat指令。不要将2進制檔案的内容儲存到變量中

                 variable1=`<file1`      #  将"file1"的内容放到"variable1"中.   

                 variable2=`cat file2`   #  将"file2"的内容放到"variable2"中.    但是這行将會fork一個新程序

3.2.4 程序替換

          程序替換則是把一個程序的輸出回饋給另一個程序 (換句話說,它把一個指令的結果發送給另一個指令).

          程序替換的一般形式: 由圓括号括起的指令

>(command)

<(command)  在"<" 或or ">" 與圓括号之間是沒有空格的. 如果加了空格将會引起錯誤資訊

程序替換能比較兩個不同指令之間的輸出:$ comm <(ls -l) <(ls -al) ;   diff <(ls $first_directory) <(ls $second_directory)

4.1 測試

      4.1.1 測試結構

               if  any_thing

               if test any_thing

               if  [ 空格分隔的變量 ]

               [ 空格分割的變量 ]     && ||  不能用在這個内建指令中  , 與 或 -a  -o

               if [[ ]]

               [[ ]]   與 或 && ||

               ((  )) 算術比較, 傳回值和 [ ] 相反 

     4.1.2 檔案類的比較

                -e     檔案存在

                -f      檔案是一個普通檔案(不是一個目錄或是一個裝置檔案)                 -s     檔案大小不為零                 -d     檔案是一個目錄                 -b     檔案是一個塊裝置(軟碟, 光驅, 等等.)                 -c     檔案是一個字元裝置(鍵盤, 數據機, 聲霸卡, 等等.)                 -p     檔案是一個 管道                 -h     檔案是一個 符号連結                 -L     檔案是一個符号連結                 -S     檔案是一個 socket                 -t      檔案( 描述符)與一個終端裝置相關

             這個測試選項可以用于檢查腳本中是否标準輸入 ([ -t 0 ])或标準輸出([ -t 1 ])是一個終端.

                 -r      檔案是否可讀 ( 指運作這個測試指令的使用者的讀權限)                  -w     檔案是否可寫 ( 指運作這個測試指令的使用者的讀權限)                  -x      檔案是否可執行 ( 指運作這個測試指令的使用者的讀權限)                  -g      檔案或目錄的設定-組-ID(sgid)标記被設定

             如果一個目錄的sgid标志被設定,在這個目錄下建立的檔案都屬于擁有此目錄的使用者組,而不必是建立檔案的使用者所屬的組。這個特性對在一個工作組裡的同
             享目錄很有用處。

                 -u     檔案的設定-使用者-ID(suid)标志被設定

             一個root使用者擁有的二進制執行檔案如果設定了設定-使用者-ID位(suid)标志普通使用者可以以root權限運作。[1] 這對需要存取系統硬體的執行程式(比如說pppd
            和cdrecord)很有用。如果沒有設定suid位,則這些二進制執行程式不能由非root的普通使用者調用。

                 -O           你是檔案擁有者                  -G           你所在組和檔案的group-id相同                 -N           檔案最後一次讀後被修改                 f1 -nt f2   檔案 f1比 f2新                 f1 -ot f2   檔案 f1比 f2舊                 f1 -ef f2   檔案 f1和 f2 是相同檔案的硬連結                 !              "非" -- 反轉上面所有測試的結果(如果沒有給出條件則傳回真).

    4.1.3  算術比較

               -eq  等于         if [ "$a" -eq "$b" ]

               -ne  不等于    if [ "$a" -ne "$b" ]

               -gt   大于        if [ "$a" -gt "$b" ]

               -ge  大于等于  if [ "$a" -ge "$b" ]

               -lt     小于       if [ "$a" -lt "$b" ]

               -le    小于等于 if [ "$a" -le "$b" ]

                <      小于(在雙括号裡使用)      (("$a" < "$b"))

                <=   小于等于 (在雙括号裡使用)(("$a" <= "$b"))

                >     大于 (在雙括号裡使用)      (("$a" > "$b"))

                >=   大于等于(在雙括号裡使用)(("$a" >= "$b"))

  4.1.4 字元串比較

       = ==等于            if [ "$a" = "$b" ]        != 不相等             if [ "$a" != "$b" ]

  < 小于,依照ASCII字元排列順序

      if [[ "$a" < "$b" ]]   符号

      if [ "$a" \< "$b" ]    内建指令  是以 要轉義

       > 大于,依照ASCII字元排列順序

      if [[ "$a" > "$b" ]]

      if [ "$a" \> "$b" ]

       -z 字元串為"null",即是指字元串長度為零。     在測試方括号裡進行 -n測試時一定要把字元串用引号起來,不然可能會出錯,可移植性不好        -n 字元串不為"null",即長度不為零            在測試方括号裡進行 -n測試時一定要把字元串用引号起來,而且如果var有空格就不好辦     4.1.5  與 或       [ ]   中: -a -o        [[ ]] 中: && ||  ,  [[ ]] 比 [ ] 更常用

4.2  流程控制

    4.2.1  for

              2種形式: for var in action or $var-list

                               for(( a=2; a<var;a++ ))    c 風格 ,var沒有$

   4.2.2 while

             2種形式: while [ ] or [[ ]] or action

                              while((  a < var ))   c 風格,var沒有$

   4.2.3 util

            util [ ] or [[ ]] or action   until [[ condition ]] 是直到conditon 成立,才不執行do done操作

   4.2.4 case

            case "$var_name" in               對變量使用""并不是強制的,因為不會發生單詞分離

            “$case1”)

               do_sth

               ;;                                         case沒有break,沒有do done

           "$case2")

              do_sth

              ;;                                            case  沒有break,沒有do done

            esac

    4.2.5 select

           select var_name in $var_list

           do

              action

              break;

           done

   4.2.6 if [ ] 或 [[ ]] 或 action 或 test

            then

                do_sth

           else if [ ] [[ ]] test action        或者elif

           then

               do_sth

          else

                do_sth

         fi

         fi    注意, 有幾個fi就要有幾個fi  ; 上面如果使用elif,那麼下面隻要一個fi就可以了  。

5.數組

    數組是多個變量的存儲,數組的變量時array[num], 等同于一般的變量var;  要通路一個數組元素,可以使用花括号來通路,即${array[xx]},0可以省略為${array}

    數組元素沒有類型,不同類型的元素可以放在同一個數組裡

   5.1 數組定義

         declare -a array

        array =()          ()表明變量是數組

   5.2 數組初始化

      5.2.1 array[0]=$var  等同于變量指派

      5.2.2 array=($var0 $var1 $var2 .....)

      5.2.3 array=([2]=$var [24]=$var)

  5.3 增加一個元素到數組                不同于c,數組可以擴充

     array=("$array[@]" "new1")  相當于,重新寫了扁數組中的所有元素

     array[${#array[@]}=new1

  5.4 調用數組

    5.4.1 ${array[@]} ${array[*]} 數組中的所有元素

             ${#array[@]} ${#array[*]}數組中元素個數

             ${array[num]} 數組中array[num]的值,

             ${array} 等同于 ${array[0]}

   5.4.2  ${array:pos:len} 數組從下标pos開始len個元素 , 即array[pos] array[pos+1]..array[pos+len-1]

             ${array[@]:0}  ${array[@]}  $array[*] 顯示數組的所有元素

   5.4.3  對資料某元素的調用

            ${array[N]:pos:len}  即 array[N]中,位置pos開始len個長度的字元

   5.4.4 删除數組的某個元素

            unset array[N]  删除array[N],等同于array[4]=

            unset array  等同于 unset array[@]  删除整個數組

  5.5  複制數組

       array_2=($array[@])

       array_2=("$array[@]")  這個會保持數組中的分割符

  5.6 判斷索引是否在數組裡

      if [ "name" in array ]   不能用 if [ -z array[name] ] 

6.1 函數

    一個函數是一個子程式,用于實作一串操作的代碼塊(code block),

     6.1.1 func_name()

              {                               有更好的可移植性 , 符合c語言的格式

              }

             function func_name

             {

             } 

     6.1.2 傳給腳本的指令行參數怎麼辦?在函數内部可以看到它們嗎?

                 除非顯示的傳給函數參數,否則函數看不到傳給腳本的參數,例如看不到$1 $2 $3

     6.1.3 函數裡變量 和 參數 的作用域

        6.1.3.1 函數定義的變量預設是global的,其作用域從“函數"被調用時"執行變量定義的地方”開始,到shell結束或被顯示删除處為止            

                    函數定義的變量也可以被顯示定義成local的,其作用域局限于函數内。

                    函數調用之前,所有在函數内聲明且沒有明确聲明為local的變量都可在函數體外可見

         6.1.3.2  函數的參數是local的

         6.1.3.3  腳本中定義的變量是global的,其作用域從"被定義"的地方開始,到shell結束或被顯示删除的地方為止

     6.1.4 函數的傳回值  $?  return的傳回值也是寫到$?裡

              func xxx

              a=$?   不能寫成a=$(func xxx)

         6.1.4.1  return     内建指令 ,傳回的最大正整數是255

                      如果沒有return ,将傳回函數最後一個執行指令的退出狀态

          6.1.4.2 為了函數可以傳回字元串或是數組,用一個可在函數外可見的變量

          6.1.4.3 rerurn 傳回的最大正整數是255 ,如何傳回更大的數值

                      一種擷取大整數的"傳回值"的辦法是簡單地将要傳回的值賦給一個全局變量

                      更優雅的做法是在函數用 echo 列印"傳回值到标準輸出",然後使用指令替換(command substitution)捕捉此值

     6.1.5 函數的輸入重定向

          函數本質上是一個代碼塊(code block), 這意味着它的标準輸入可以被重定向

         Function ()    {     ...    } < file    # 也試一下這個:   Function ()    {     {       ...      } < file  }

7.1 内部變量

      OFS=\r\n

8.1 常用指令

     find

     rev

     md5sum

     printf printf “ string  %d %u %s ”  $var1 $var2 $var3

     head   head filename -n N 列印頭N行 ; head filename -n -N 列印頭N行之後的所有行

     tail     tail filename -n M 列印結尾M行; tail filename -n +M 列印頭M行之後的所有行

     bc     hex=`echo "obase=16;ibase=10; $n" | bc`   十進制轉化為16進制  ; echo $1+$2 | bc 浮點數計算

     tput  光标屬性

     tput cup row_num col_num  将光标移到 row行 col列位置

     tput cols  檢視目前序列槽tty的列寬col

     date +%a +%A +%b +%B 顯示目前的時間,不同的顯示格式 。  man date

9.1 全局變量

   $LOGNAME