linux&shell

Linux常用命令

  • 登陸時顯示信息放在/etc/motd和/etc/profile.d/xxx.sh
    • motd放置字符串
    • profile.d下放置腳本文件
  • echomysql

    • echo -e 處理特殊字符。若字符串中出現下面字符。則特別加以處理,而不會將它當成通常文字輸出:
      • \a 發出警告聲;
      • \b 刪除前一個字符。
      • \c 最後不加上換行符號;
      • \f 換行但光標仍舊停留在原來的位置。
      • \n 換行且光標移至行首。
      • \r 光標移至行首。但不換行;
      • \t 插入tab;
      • \v 與\f一樣;
      • \ 插入\字符;
      • \nnn 插入nnn(八進制)所表明的ASCII字符;
    • echo -n 不換行輸出
  • date +%T 以格式化輸出當前時間linux

  • ls -lrt 按時間升序列表顯示
  • dirname 路徑 dirname $0
  • basename 文件名稱
  • 在環境變量文件裏使用alias vi=’vim’就能夠實現vi取代vim命令

Shell

Shell腳本的創建與運行

Shell 腳本的創建

  • 使用文本編輯器編輯腳本文件
    • vi script-file
  • 爲腳本文件加入可運行權限
    • chmod +x script-file

Shell 腳本的運行

  • 在子Shell中運行
    • 變量及結果在結束時從內存銷燬,外部shell沒法引用
    • bash script-file
    • 或者./script-file
  • 在當前Shell中運行
    • 當前shell可繼續引用運行結束shell的變量及結果
    • source script-file
    • . script-file

Shell腳本的編碼規範

以 #! 開頭:通知系統用何解釋器運行此腳本

  • #!/bin/bash
  • 或者#!/bin/sh

以凝視形式說明例如如下的內容:

  • # 腳本名稱
  • # 腳本功能
  • # 做者及聯繫方式
  • # 版本號更新記錄
  • # 版權聲明
  • # 對算法作簡要說明(假設是複雜腳本)
    • 演示樣例git

      #!/bin/bash
      # This is the first Bash shell program 
      # Scriptname: greetings.sh
      echo
      echo -e "Hello $LOGNAME, \c"
      echo    "it's nice talking to you."
      echo -n "Your present working directory is: "
      pwd # Show the name of present directory
      echo
      echo -e "The time is `date +%T`!. \nBye"
      echo
    • 時間同步shell腳本算法

      #!/bin/bash
      ## Script Name:/etc/cron.daily/ntpdate
      # 使用NTP的client命令ntpdate與遠程NTPserver進行同步
      # 也可以用局域網內的NTPserver替換 pool.ntp.org
      /usr/sbin/ntpdate -s pool.ntp.org
      # 更改硬件時鐘時都會記錄在/etc/adjtime文件裏
      # 使hwclock依據先前的記錄來估算硬件時鐘的誤差。
      # 並用來校訂眼下的硬件時鐘
      /sbin/hwclock --adjust
      # 將系統時鐘同步到硬件時鐘
      /sbin/hwclock –systohc

腳本調試方法

在 bash 調用腳本時使用參數

  • bash [-x] [-n] [-v] scriptName
    • sh –x 腳本名
      • 該選項可以使用戶跟蹤腳本的運行。此時 shell 對腳本中每條命令的處理過程爲:先運行替換,而後顯示,再運行它。shell 顯示腳本中的行時。會在行首加入一個加號 「 + 」
      • 以調試模式運行腳本
    • sh –v 腳本名
      • 在運行腳本以前,按輸入的原樣打印腳本中的各行
      • 顯示腳本中每個原始命令行及其運行結果
    • sh –n 腳本名
      • 對腳本進行語法檢查。但不運行腳本。

        假設存在語法錯誤,shell 會報錯。假設沒有錯誤,則不顯示不論什麼內容sql

      • 對腳本進行語法檢查

在腳本中使用 bash 內置的 set 命令使整個或部分腳本處於調試模式

  • 開啓:set [-x] [-n] [-v]
    • 在腳本內使用set命令開啓調試選項
      • set -x :顯示由shell運行的命令及其參數
      • set -v :顯示由shell讀入的命令行
      • set -n :讀取命令但不運行他們。用於語法檢查
  • 結束:set [+x] [+n] [+v]
    • 在腳本內使用set命令關閉已開啓的調試選項
      • set +x
      • set +v
      • set +n
  • 演示樣例shell

    #!/bin/bash
        # This is the first Bash shell program 
        # Scriptname: greetings.sh
        set -x ### Turn ON debug mode ###
        echo
        echo -e "Hello $LOGNAME, \c"
        echo    "it's nice talking to you."
        echo -n "Your present working directory is: "
        pwd # Show the name of present directory
        echo
        set +x ### Turn OFF debug mode ###
        echo -e "The time is `date +%T`!. \nBye"
        echo

Shell腳本的類型

非交互式腳本

  • 不需要讀取用戶的輸入, 也不用向用戶反饋某些信息
  • 每次運行都是可預見的, 因爲它不讀取用戶輸入, 參數是固定的
  • 可以在後臺運行

交互式腳本

  • 腳本可以讀取用戶的輸入, 實時向用戶反饋信息(輸出某些信息)
  • 這種腳本更靈活, 每次運行時的參數可由用戶動態設定
  • 用戶界面更友好,但不適用於本身主動化任務(如cron任務)

Shell變量操做

  • 變量替換擴展
    • 變量測試
    • 變量的字符串操做
    • 變量的間接引用
  • 變量的數值計算
    • $[expression]
    • $((expression))
    • expr
    • let
    • declare -i
  • 輸入
    • 變量賦值
      • name=value
      • readonly
    • 從標準輸入讀取
      • read
  • 輸出
    • echo
    • printf

變量替換擴展

變量測試

演示樣例

字符串計數、截取

演示樣例

字符串替換

演示樣例

變量的間接引用

  • 經過 str2 的值來引用 str1 的值express

    • 錯誤演示樣例編程

      str1="Hello World"
      str2=str1
      echo $str2
    • 正確演示樣例vim

      str1="Hello World"
      str2=str1
      newstr=${!str2}
      echo $newstr
      Hello World
      或
      echo ${!str2}
      Hello World
      或
      eval newstr=\$$str2
      echo $newstr
      Hello World
      或
      eval echo \$$str2
      Hello World
  • x=」CENTOS」centos

  • CENTOS_URL=」http://mirrors.163.com/centos/」
  • 經過 x 的值來引用 CENTOS_URL 的值

    # bash2.0以上才支持
    newstr=${x}_URL
    echo $newstr
    CENTOS_URL
    echo ${!newstr}
    http://mirrors.163.com/centos/ 
    或
    eval newstr=\$${x}_URL
    echo $newstr
    或
    eval echo \$${x}_URL

Shell內置命令——eval

eval arg1 [arg2] … [argN]
* 對參數進行兩次掃描和替換
* 將所有的參數鏈接成一個表達式。並計算或運行該表達式
* 參數中的不論什麼變量都將被展開

listpage="ls -l | more"
    eval $listpage

    eval $(ssh-agent)

    eval newstr=\$$str2
    eval echo \$${x}_URL

Shell 變量的分類

  • 用戶自定義變量
    • 由用戶自定義、改動和使用
  • Shell 環境變量
    • 由系統維護,用於設置用戶的Shell工做環境
    • 僅僅有少數的變量用戶可以改動其值
  • 位置參數變量(Positional Parameters)
    • 經過命令行給程序傳遞運行參數
    • 可用 shift 命令實現位置參數的遷移
  • 專用參數變量(Special Parameters)
    • Bash 提早定義的特殊變量
    • 用戶不能改動其值

位置變量

  • 是一組特殊的內置變量
    • 跟在腳本名後面的用空格隔開的每個字符串
    • 11 9 表示第9個參數值
    • 1010 {11} 表示第11個參數值。 ……
  • 位置參數的用途
    • 從 shell 命令/腳本 的命令行接受參數
    • 在調用 shell 函數時爲其傳遞參數

專用參數變量

  • 命令行參數相關

    $* 獲取當前shell腳本所有傳參的參數,將所有位置參量當作一個字符串(以空格間隔)。至關於""$1$2$3$4$5 。 $@ 將每個位置參量當作單獨的字符串(以空格間隔)"$!" "$2" "...."。 "$*" 將所有位置參量當作一個字符串(以$IFS間隔)。 "$@" 將每個位置參量當作單獨的字符串(以空格間隔) 。 $0 命令行上輸入的Shell程序名。

    $# 表示命令行上參數的個數。

  • 進程狀態相關

    $?  表示上一條命令運行後的返回值
    $$  當前進程的進程號
    $!  顯示運行在後臺的最後一個做業的 PID 
    $_  在此以前運行的命令或腳本的最後一個參數
  • 演示樣例


位置參數和 shift 命令

  • shift [n]
  • 將位置參量列表依次左移n次。缺省爲左移一次
  • 一旦位置參量列表被移動,最左端的那個參數就會從列表中刪除
  • 常常與循環結構語句一塊兒使用,以便遍歷每個位置參數

    #!/bin/sh
    # ScriptName: pp_shift.sh
    # To test Positional Parameters & Shift.
    echo "The script name is :  $0"
    echo '$1'=$1,'$2'=$2,'$3'=$3,'$4'=$4   --   '$#'="$#" 
    echo '$@': "$@" 
    shift              # 向左移動所有的位置參數1次
    echo '$1'=$1,'$2'=$2,'$3'=$3,'$4'=$4   --   '$#'="$#"
    echo '$@': "$@"
    shift 2            # 向左移動所有的位置參數2次
    echo '$1'=$1,'$2'=$2,'$3'=$3,'$4'=$4   --   '$#'="$#"
    echo '$@': "$@"
    
    $ ./pp_shift.sh  1 b 3 d 4 f

退出/返回狀態

$?:返回上一條語句或腳本運行的狀態

  • 0:成功
  • 1-255:不成功
  • 1:運行正確
  • 126:命令或腳本沒有運行權限
  • 127:命令沒有找到

exit 命令

  • exit 命令用於退出腳本或當前Shell
  • exit n
    • n 是一個從 0 到 255 的整數
    • 0 表示成功退出,非零表示遇到某種失敗
  • 返回值 被保存在狀態變量 $? 中

演示樣例

$ echo $$ # 顯示當前進程的 PID 9245 $ echo $? # 顯示在此以前運行的命令的返回值 0 $ bash # 調用子Shell $ echo $$ # 顯示當前進程的 PID 9474 $ exit 1 # 指定返回值並返回父Shell $ echo $? # 顯示上一個Shell/腳本的返回值 1 $ list # 運行不存在的命令 bash: list: command not found $ echo $? 127 $ touch bbb.sh $ ./bbb.sh # 運行不具備運行權限的命令 bash: ./bbb.sh: Permission denied $ echo $?

126

read

  • 從鍵盤輸入內容爲變量賦值
    • read [-p 「信息」] [var1 var2 …]
    • 若省略變量名,則將輸入的內容存入REPLY變量
  • 結合不一樣的引號爲變量賦值
    • 雙引號 」 」:贊成經過$符號引用其它變量值
    • 單引號 ’ ’:禁止引用其它變量值。$視爲普通字符
    • 反撇號 :將命令運行的結果輸出給變量

演示樣例

#!/bin/bash # This script is to test the usage of read # Scriptname: ex4read.sh echo "=== examples for testing read ===" echo -e "What is your name?

\c" read name echo "Hello $name" echo echo -n "Where do you work? " read echo "I guess $REPLY keeps you busy!" echo read -p "Enter your job title: " echo "I thought you might be an $REPLY." echo echo "=== End of the script ==="

僅僅讀變量

  • 是指不能被清除或又一次賦值的變量
  • readonly variable

演示樣例

[lrj@centos1 ~]$ myname=Osmond
    [lrj@centos1 ~]$ echo $myname
    Osmond
    [lrj@centos1 ~]$ readonly myname
    [lrj@centos1 ~]$ unset myname
    -bash: unset: myname: cannot unset: readonly variable
    [lrj@centos1 ~]$ myname="Osmond Liang"
    -bash: myname: readonly variable

同一時候輸出多行信息

  • 使用 echo

  • 使用 here file

整數運算

  • Bash 變量沒有嚴格的類型定義
    • 本質上 Bash 變量都是字符串
  • 若一個字面常量或變量的值是純數字的。不包括字母或其它字符, Bash可以將其視爲長整型值,並可作算數運算和比較運算。
  • Bash 也贊成顯式地聲明整型變量
    • declare -i 變量名

算數運算符

算術運算擴展—在此沒有空格的問題

$ var=test
    $ echo $var
    test
    $ echo $varAA
    $varAA
    $ echo ${var}AA
    testAA

    $ ls
    a b c
    $ echo $(ls)
    a b c
    $ echo `ls`
    a b c

Shell內置命令

let

  • let 內置命令用於算術運算

    num2=1; echo $num2
    let num2=4+1; echo $num2
    let num2=$num2+1; echo $num2
  • 賦值符號和運算符兩邊不能留空格!
  • 假設將字符串賦值給一個整型變量時。則變量的值爲 0
  • 假設變量的值是字符串,則進行算術運算時設爲 0

    let num2=4 + 1
    let "num2=4 + 1" # 用引號忽略空格的特殊含義
  • 用 let 命令進行算術運算時。最好加雙引號

expr

  • 通用的表達式計算命令
  • 表達式中參數與操做符必須以空格分開。
  • 表達式中的運算可以是算術運算,比較運算,字符串運算和邏輯運算。

    expr 5 % 3
    expr 5 \* 3        # 乘法符號必須被轉義
    expr 2 + 5 \* 2 - 3 % 2
    expr \( 2 + 5 \) \* 2 – 3  # 括號必須被轉義

浮點數運算

  • bash 僅僅支持整數運算
  • 可以經過使用 bc 或 awk 工具來處理浮點數運算

    n=$(echo "scale=3; 13/2" | bc )
    echo $n
    m=`awk 'BEGIN{x=2.45;y=3.123;printf "%.3f\n", x*y}'`
    echo $m

printf

  • printf 可用來按指定的格式輸出變量
  • printf format 輸出參數列表

演示樣例

數組變量

  • Bash 2.x 以上支持一維數組,下標從 0 開始
  • 使用 declare 聲明或直接給變量名加下標來賦值

    declare -a variable
    variable=(item1 item2 item2 ... )
  • 數組的引用

    ${variable[n]}

演示樣例

declare

  • 內置命令 declare 可用來聲明變量
  • declare [選項] variable[=value]

演示樣例

declare myname=osmond
    declare –r myname=osmond
    unset myname
    declare myname=「Osmond Liang"
    declare –x myname2=lrj
    myname2=lrj
    declare –x myname2

變量及相關命令小結




條件測試

  • 條件測試可以推斷某個特定條件是否知足
    • 測試以後通常會依據不一樣的測試值選擇運行不一樣任務
  • 條件測試的種類
    • 命令成功或失敗
    • 表達式爲真或假
  • 條件測試的值
    • Bash中沒有布爾類型變量
      • 退出狀態爲 0 表示命令成功或表達式爲真
      • 非0 則表示命令失敗或表達式爲假
    • 狀態變量 $? 中保存了退出狀態的值

演示樣例

條件測試語句

  • 語句
    • 格式1: test <測試表達式>
    • 格式2: [ <測試表達式> ]
    • 格式3: [[ <測試表達式> ]] (bash 2.x 版本號以上)
  • 說明
    • 格式1 和 格式2 是等價的,格式3是擴展的 test 命令
    • 在 [[ ]] 中可以使用通配符進行模式匹配
    • &&, ||, <, 和>可以正常存在於[[ ]]中。但不能在 [] 中出現
    • [和[[以後的字符必須爲空格,]和]]以前的字符必須爲空格
    • 要對整數進行關係運算也可以使用 (()) 進行測試

條件測試操做符

  • 條件測試表達式中可用的操做符
    • 文件測試操做符
    • 字符串測試操做符
    • 整數二元比較操做符
    • 使用邏輯運算符

文件測試

  • 測試:文件是否存在。文件屬性,訪問權限等

字符串測試

  • 字符串按從左到右相應字符的ASCII碼進行比較

字符串空值檢查

檢查空值

檢查非空值

整數測試

  • 操做符兩邊必須留空格!


  • 操做符兩邊的空格可省略

演示樣例


邏輯測試

演示樣例


流程控制——分支

  • 流程控制語句
    • 分支
      • if 條件語句
      • case 選擇語句
    • 循環
      • for 循環語句
      • while 循環語句
      • until 循環語句
      • select 循環與菜單
    • 循環控制
      • break 語句
      • continue 語句
    • 位置參數處理
      • shift 命令
      • getopts 命令

if 語句

if expr1      # 假設 expr1 爲真(返回值爲0)
    then          # 那麼
       commands1  # 運行語句塊 commands1
    elif expr2    # 若 expr1 不真。而 expr2 爲真
    then          # 那麼
       commands2  # 運行語句塊 commands2
     ... ...      # 可以有多個 elif 語句 
    else          # else 最多僅僅能有一個
       commands4  # 運行語句塊 commands4
    fi            # if 語句必須以單詞 fi 終止
  • elif 可以有隨意多個(0 個或多個)
  • else 最多僅僅能有一個(0 個或 1 個)
  • if 語句必須以 fi 表示結束
  • exprX 一般爲條件測試表達式;也可以是多個命令。以最後一個命令的退出狀態爲條件值。
  • commands 爲可運行語句塊,假設爲空,需使用 shell 提供的空命令 「 : 」,即冒號。該命令不作不論什麼事情,僅僅返回一個退出狀態 0
  • if 語句可以嵌套使用

演示樣例






case語句

case expr in # expr 爲表達式。關鍵詞 in 不要忘!
      pattern1)  # 若 expr 與 pattern1 匹配。注意括號
       commands1 # 運行語句塊 commands1
       ;;        # 跳出 case 結構
      pattern2)  # 若 expr 與 pattern2 匹配
       commands2 # 運行語句塊 commands2
       ;;        # 跳出 case 結構  
       ... ...    # 可以有隨意多個模式匹配
      *)         # 若 expr 與上面的模式都不匹配
       commands  # 運行語句塊 commands
       ;;        # 跳出 case 結構
    esac         # case 語句必須以 esac 終止
  • 表達式 expr 按順序匹配每個模式,一旦有一個模式匹配成功,則運行該模式後面的所有命令,而後退出 case。
  • 假設 expr 沒有找到匹配的模式。則運行缺省值 「 ) 」 後面的命令塊 ( 類似於 if 中的 else );「 ) 」 可以不出現。
  • 所給的匹配模式 pattern 中可以含有通配符和「 | 」。

  • 每個命令塊的最後必須有一個雙分號。可以獨佔一行,或放在最後一個命令的後面。





流程控制——循環

for variable in list 
    # 每一次循環。依次把列表 list 中的一個值賦給循環變量
    do          # 循環體開始的標誌
      commands  # 循環變量每取一次值,循環體就運行一遍
    done        # 循環結束的標誌。返回循環頂部
  • 列表 list 可以是命令替換、變量名替換、字符串和文件名稱列表 ( 可包括通配符 )。每個列表項以空格間隔
  • for 循環運行的次數取決於列表 list 中單詞的個數
  • 可以省略 in list 。省略時至關於 in 「$@」

  • 首先將 list 的 item1 賦給 variable

    • 運行do和done之間的 commands
  • 而後再將 list 的 item2 賦給 variable
    • 運行do和done之間的 commands
      *如此循環,直到 list 中的所有 item 值都已經用完

演示樣例









break 和 continue

  • break [n]
    • 用於強行退出當前循環
    • 假設是嵌套循環。則 break 命令後面可以跟一數字 n。表示退出第 n 重循環(最裏面的爲第一重循環)
  • continue [n]
    • 用於忽略本次循環的剩餘部分。回到循環的頂部,繼續下一次循環
    • 假設是嵌套循環,continue 命令後面也可跟一數字 n,表示回到第 n 重循環的頂部

演示樣例


for循環(C語言型)語法

for ((expr1;expr2;expr3)) # 運行 expr1
    do # 若 expr2的值爲真時進入循環,不然退出 for循環
      commands  # 運行循環體,以後運行 expr3
    done        # 循環結束的標誌,返回循環頂部
  • 一般 expr1和 expr3是算數表達式; expr2是邏輯表達式
  • expr1 僅在循環開始之初運行一次
  • expr2 在每次運行循環體以前運行一次
  • expr3 在每次運行循環體以後運行一次

  • 首先運行 expr1

  • 運行 expr2
    • 其值爲假時,終止循環
    • 其值爲真時。運行do和done之間的 commands
    • 運行expr3,進入下一次循環

演示樣例



while 循環語句

while expr  # 運行 expr
    do # 若expr的退出狀態爲0。進入循環,不然退出while
      commands  # 循環體
    done        # 循環結束標誌,返回循環頂部

演示樣例


* While 和輸入重定向

* 使用管道爲 while 傳遞輸入

until 循環語句

until expr  # 運行 expr
    do # 若expr的退出狀態非0。進入循環,不然退出until
      commands  # 循環體
    done        # 循環結束標誌,返回循環頂部

演示樣例




  • 將循環結果經過管道傳遞給其它命令處理(done |)

  • 後臺運行循環(done &)

循環與菜單

  • 通常地。使用 while 循環配合 case實現
  • Bash 提供了專門的 select 循環
    • select 循環主要用於建立菜單
    • select 是個無限循環
      • 一般要配合 case 語句處理不一樣的選單及退出
      • select 循環的退出
        • 按 ctrl+c 退出循環
        • 在循環體內用 break 命令退出循環
        • 或用 exit 命令終止腳本

演示樣例

  • 使用while循環實現菜單

循環結構——select 語法

select variable in list 
    do          # 循環開始的標誌
      commands  # 循環變量每取一次值,循環體就運行一遍
    done        # 循環結束的標誌
  • 按數值順序排列的菜單項(list item)會顯示到標準輸出
  • 菜單項的間隔符由環境變量 IFS 決定
  • 用於引導用戶輸入的提示信息存放在環境變量 PS3 中
  • 用戶輸入的值會被存儲在內置變量 RELAY 中
  • 用戶直接輸入回車將又一次顯示菜單
  • 與 for 循環類似。省略 in list 時等價於 in 「$*」

演示樣例




位置參數和命令行參數處理

  • 在腳本中常用流程控制處理位置參數
    • 循環結構:while、for
    • 多分支結構:case
  • 在腳本中常用例如如下命令配合位置參數處理
    • shift
    • getopts

演示樣例

  • 參數位置遍歷




  • 位置參數處理舉例

選項和參數

  • mybackup -z -c /etc/mybackup.conf -r -v ./foo.txt ./mydir
  • -z是個選項(option)。以減號開始的單字符
  • -c也是個選項,/etc/mybackup.conf 是該選項的附加參數(additional argument )
  • -r和-v也是選項,且不帶附加參數
  • ./foo.txt 和 ./mydir 是腳本的處理對象,他們是不與不論什麼選項相關的參數,在POSIX®標準中稱其爲「操做 對象/數」(operands)

  • 依照Linux的命令行書寫規範。例如如下命令行

    • mybackup -z -c /etc/mybackup.conf -r -v ./foo.txt ./mydir
  • 也可以寫成例如如下的等價形式

    • mybackup -zr -c /etc/mybackup.conf -v ./foo.txt ./mydir
    • mybackup -zv -c /etc/mybackup.conf -r ./foo.txt ./mydir
    • mybackup -vr -c /etc/mybackup.conf -z ./foo.txt ./mydir
    • mybackup -vz -c /etc/mybackup.conf -r ./foo.txt ./mydir
    • mybackup -zrv -c /etc/mybackup.conf ./foo.txt ./mydir

    - mybackup -zrvc /etc/mybackup.conf ./foo.txt ./mydir

  • 用戶使用本身的代碼分析這些選項將變得十分困難
  • Shell的內置命令getopts可以識別所有常見的選項格式,爲用戶處理選項和參數提供了方便

內置命令——getopts

  • getopts OPTSTRING VARNAME [ARGS…]
  • OPTSTRING
    • 是由若干有效的選項標識符組成的選項字符串
    • 若某選項標識符後有冒號,則表示此選項有附加參數
    • 若整個字符串前有冒號,將使用「安靜」的錯誤模式
  • VARNAME :每次匹配成功的選項保存在變量中
  • ARGS : 參數列表。省略時爲 」$@」

  • getopts c:zrv opt

  • getopts :c:zrv opt

  • getopts的運行過程

    • 一般需要以循環的方式運行屢次 getopts 來解析位置參數中的選項以及可能存在的選項附加參數
      *每次調用 getopts,將會處理參數列表中的「下一個」選項
      • 將選項存儲在VARNAME變量中
      • 將此選項相應的附加參數存儲在環境變量OPTARG中
      • 對環境變量OPTIND進行自增操做,使 $OPTIND 老是指向原始參數列表中「下一個」要處理的元素位置
      • VARNAME OPTSTRING的所有選項均不匹配,則作「invalid option」的錯誤設置
      • 若某選項的參數不存在。則作「required argument not found」的錯誤設置
  • getopts的錯誤報告模式

  • 冗餘(Verbose)模式( OPTSTRING 不以:開頭)
    • 「invalid option」
      • VARNAME=「?」 ; unset OPTARG
    • 「required argument not found」
      • VARNAME=「?」 ; unset OPTARG 並輸出錯誤信息
  • 安靜(Silent)模式( OPTSTRING 以:開頭)
    • 「invalid option」
      • VARNAME=「?」 ; OPTARG=‘無效的選項字符’
    • 「required argument not found」
      • VARNAME=「:」 ; OPTARG=‘與參數相應的選項字符’

while循環與getopts處理

while getopts  OPTSTRING  VARNAME
    do
      case $VARNAME in 
        …) ………… ;;
        …) ………… ;;
        :) ………… ;;
       \?) ………… ;;
      esac
    done
  • getopts 返回假時終止 while 循環
    • 當 getopts 遭遇到第一個非選項參數時終止解析
    • 當 getopts 遭遇到 「–」參數時終止解析

getopts的注意事項

  • getopts 不能解析 GNU-style 長參數 (–myoption)
  • getopts從不改變原始位置參數
    • 若但願移動位置參數,需手工運行 shift
  • getopts會本身主動對變量 OPTIND 作自增處理
    • OPTIDX的初始值爲 1
    • 若要又一次解析命令行參數,需將OPTIDX的值置爲 1
  • getopts 遭遇到第一個非選項參數時終止解析
    • 終止解析後運行命令
      • shift ((OPTIND-1))
    • 可以使 」$@」 僅僅包括「操做 對象/數」(operands

演示樣例

  • 演示樣例1

    #!/bin/bash
    ## filename : pp_parse_getopts_1.sh
    while getopts  "abc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    echo "Resetting"
    OPTIND=1
    while getopts  "bc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    
    $ ./pp_parse_getopts_1.sh -a -bc foo -f "foo bar" -h –gde
    $ ./pp_parse_getopts_1.sh -abf "foo bar" -h -gde –c
    $ ./pp_parse_getopts_1.sh -abf 「foo bar」 -h –c -gde
  • 演示樣例2

    #!/bin/bash
    ## filename : pp_parse_getopts_2.sh
    while getopts  ":abc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    echo "Resetting"
    OPTIND=1
    while getopts  ":bc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    
    $ ./pp_parse_getopts_2.sh -a -bc foo -f "foo bar" -h -gde
    $ ./pp_parse_getopts_2.sh -abf "foo bar" -h -gde –c
    $ ./pp_parse_getopts_1.sh -abf 「foo bar」 -h –c -gde

* 演示樣例3

#!/bin/bash
    ## filename : mybackup_getopts.sh
    while getopts :zc:x:rv opt
    do
      case $opt in
        c) ConfFile=$OPTARG       ;;
        x) ExcludeFile=$OPTARG    ;;
        z) Compress=true          ;;
        r) Recursive=true         ;;
        v) Verbose=true           ;;
        :)
          echo "$0: Must supply an argument to -$OPTARG." >&2
          exit 1
          ;;
        \?) echo "Invalid option -$OPTARG ignored." >&2   ;;
      esac
    done

    shift $((OPTIND-1)) ; echo $0 ; echo "$@"
  • 演示樣例4

    #!/bin/bash
    ## filename : mybackup_getopts2.sh
    while getopts :zc:x:rv opt
    do
      case $opt in
        c) if [[ $OPTARG = -* ]]; then  ((OPTIND--)) ;  continue ;  fi
           ConfFile=$OPTARG       ;;
        x) ExcludeFile=$OPTARG    ;;
        z) Compress=true          ;;
        r) Recursive=true         ;;
        v) Verbose=true           ;;
        :)
          echo "$0: Must supply an argument to -$OPTARG." >&2
          exit 1
          ;;
        \?) echo "Invalid option -$OPTARG ignored." >&2   ;;
      esac
    done
    
    shift ((OPTIND-1)) ; echo $0 ; echo "$@"

函數

  • 爲了不大型腳本變得複雜、晦澀而使用函數
  • 將大型腳本代碼切割成小塊。將這些被命名的代碼塊稱爲函數
    • 一個函數就是一個子程序。用於完畢特定的任務
      • 如:加入一個用戶、推斷用戶是否爲管理員 等
  • 函數定義以後可以被使用它的主程序調用
    • 調用函數的方法與運行Shell命令無異
    • 可以在Shell腳本中調用(函數需先定義然後調用)
    • 在命令行上直接調用(定義函數的文件需先載入

合理使用Shell函數

  • 簡化程序代碼,實現代碼重用
    • 實現一次定義屢次調用。如:is_root_user()函數可以由不一樣的shell腳本反覆使用。
  • 實現結構化編程
    • 使腳本內容更加簡潔。加強程序的易讀性
  • 提升運行效率
    • 將常用的功能定義爲多個函數並將其保存在一個文件裏
      • 類似其它語言的「模塊」文件
    • 在 ~/bashrc 或命令行上使用 source 命令調用這個文件
    • 此文件裏定義的多個函數一次性地調入內存,從而加快運行速度

函數的定義和調用

函數定義

函數調用

  • 僅僅需輸入函數名就能夠調用函數
    • 函數名
    • 函數名 參數1 參數2 …
  • 函數必須在調用以前定義

函數的存儲和顯示

  • 函數的存儲
    • 函數和調用它的主程序保存在同一個文件裏
      *函數的定義必須出現在調用以前
      *函數和調用它的主程序保存在不一樣的文件裏
      • 保存函數的文件必須先使用 source 命令運行,以後才幹調用當中的函數
  • 函數的顯示
    • 顯示當前Shell可見的所有函數名
      • $ declare -F
    • 顯示當前Shell可見的所有(指定)的函數定義
      • $ declare -f
      • $ declare -f

演示樣例

  • 函數的定義和調用

    • 演示樣例1

      #!/bin/bash
      ## filename: all_in_one_backup_select.sh
      ### User define Function (UDF) ###
      sql_bak  () { echo "Running mysqldump tool..."; }
      sync_bak () { echo "Running rsync tool..."; }
      git_bak  () { echo "Running gistore tool..."; }
      tar_bak  () { echo "Running tar tool..."; }
      ### Main script starts here ###
      PS3="Please choose a backup tools : "
      select s in  mysqldump rsync gistore tar quit ; do
        case $REPLY in
             1) sql_bak  ;;
             2) sync_bak ;;
             3) git_bak  ;;
             4) tar_bak  ;;
             5) exit     ;;
        esac
      done
    • 演示樣例2

      #!/bin/bash
      ## filename: /root/bin/my_backup_functions.sh
      ### User define Function (UDF) ###
      sql_bak  () { echo "Running mysqldump tool..."; }
      sync_bak () { echo "Running rsync tool..."; }
      git_bak  () { echo "Running gistore tool..."; }
      tar_bak  () { echo "Running tar tool..."; }
    • 演示樣例3

      #!/bin/bash
      ## filename: all_in_one_backup_select.sourcefunc.sh
      source /root/bin/my_backup_functions.sh
      ### Main script starts here ###
      PS3="Please choose a backup tools : "
      select s in  mysqldump rsync gistore tar quit ; do
        case $REPLY in
             1|[mM]ysqldump) sql_bak  ;;
             2|[rR]sync)     sync_bak ;;
             3|[gG]istore)   git_bak  ;;
             4|[tT]ar)       tar_bak  ;;
             5) exit     ;;
        esac
      done

函數與變量

  • 參數(Arguments)
    • 調用函數時。使用位置參數的形式爲函數傳遞參數
    • 函數內的 1 {n} 、 @ 表示其接收的參數
    • 函數調用結束後位置參數 1 {n} 、 @ 將被重置爲調用函數以前的值
    • 在主程序和函數中,$0始終表明腳本名
  • 變量(Variables)
    *函數內使用 local 聲明的變量是局部(Local)變量
    *局部變量的做用域是當前函數以及其調用的所有函數
    • 函數內未使用 local 聲明的變量是全局(Global)變量
      *即主程序和函數中的同名變量是一個變量(地址一致

演示樣例

  • 函數與位置參數

    • 演示樣例1

      #!/bin/bash
      ## filename: pp_and_function.sh
      echo "===Print positional parameters in main :"
      echo "$0: $*"
      pp1(){
        echo 'f1--Print $* parameters in fun1 :' ; echo "$0: $*"
      }
      pp2(){
        echo 'f2--Print $* parameters in fun1 :' ; echo "$0: $*"
        pp1 1st 2nd 3th 4th 5th 6th 7th 8th 9th
        echo 'f2--Print $* parameters in fun1 :' ; echo "$0: $*"
      }
      pp1 1 2 3 4 5 6 7 8 9
      echo "===Print positional parameters in main :"
      echo "$0: $*"
      pp2 I II III IV V VI VII VIII IX
      
      ./pp_and_function.sh  a b c d e f g h i
    • 演示樣例2

      #!/bin/bash
      ## filename: function_max.sh
      # User define Function (UDF)
      usage () {
        echo "List the MAX of the positive integers in command line. "
        echo "Usage: `basename $0` <num1> <num2> [ <num3> ... ]"
        exit
      }
      max () {
        [[ -z $1 || -z $2 ]] && usage
        largest=0
        for i ; do  ((i>largest)) && largest=$i ; done
      }
      ### Main script starts here ###
      max "$@"
      echo "The largest of the numbers is $largest."
      
      ./function_max.sh  1 58 111 32768 66
  • 因爲largest變量在函數max內沒有使用local聲明,因此它是全局的

函數的結束與返回值

  • 當函數的最後一條命令運行結束函數即結束
    • 函數的返回值就是最後一條命令的退出碼
    • 其返回值被保存在系統變量$?中
  • 可以使用 return 或 exit 顯式地結束函數
    • return [N]
      • return 將結束函數的運行
      • 可以使用 N 指定函數返回值
    • exit [N]
      • exit 將中斷當前函數及當前Shell的運行
      • 可以使用 N 指定返回值

演示樣例

#!/bin/bash
    ## filename: function_max2.sh
    # User define Function (UDF)
    max2 () {
      if [[ -z $1 || -z $2 ]] ; then
        echo  "Need 2 parameters to the function." ; exit
      fi
      [ $1 -eq $2 ] &&
           { echo "The two numbers are equal." ; exit ; }
      (($1>$2)) && return $1 || return $2
    }
    ### Main script starts here ###
    read -p "Please input two integer numbers  : " n1 n2
    echo "n1=$n1 , n2=$n2「
    max2 $n1 $n2
    return_val=$?
    echo "The larger of the two numbers is $return_val."

函數返回值

  • 使用全局變量引用函數的值不利於結構化編程
  • 使用 return 或 exit 僅僅能返回整數值
  • 使用標準輸出實現函數的返回值
    • 是一種通用的方法。既能返回整數又能返回字符串
    • 函數結束前使用 echo 命令將結果顯示到標準輸出
    • 調用函數時使用例如如下的格式將函數的輸出結果存到變量 RES 中,以後即可使用變量 $RES 的值(或輸出、或運行測試、或進一步處理等)
    • RES=$(functionName)
    • echo $RES

演示樣例

  • 使用標準輸出返回函數值

    #!/bin/bash
    ## filename: function_to-upper.sh
    # User define Function (UDF)
    to_upper () {
        local str="$@"
        local output
        output=$(tr '[a-z]' '[A-Z]'<<<"${str}")
        echo $output
    }
    ### Main script starts here ###
    to_upper "This Is a TEST"
    
    res=$(to_upper "$@")
    echo "$res"
    
    res=$(to_upper "$1")
    [[ $res == "YES" ]] && echo "Continue..." || echo "Stop"
    
    ./function_to-upper.sh YES we are
    ./function_to-upper.sh No we are not
  • 系統INIT 啓動腳本的結構——/etc/rc.d/init.d/*

相關文章
相關標籤/搜索