bash的一些memo

  • 很好的東西: bash能夠用<(命令) 或者 >(命令) 來生成一個暫時管道文件,用於任何須要文件的地方。 例如html

    gcc -x c <(cat <<EOF
    #include <stdio.h>
    int main() {
        printf("hello\n");
        return 0;
    }
    EOF
    )

    就至關於作了個臨時文件ttt而後執行gcc -x c ttt。這個-x c僅僅是告訴他按照C代碼編譯。c++

  • while語句裏的變量範圍shell

    while語句放在管道後面時,其中的循環裏的變量沒法傳到外部,例如:編程

    XXX=1
    (echo 2; echo 3) | while read v; do XXX=$v; done; 
    echo $XXX

    結果依然是1api

    爲了解決這個毛病,得把while放在前面,同時得用 <空格<() Process Substitution。例如:數組

    XXX=1
    while read v; do XXX=$v; done < <(echo 2; echo 3)
    echo $XXX

    結果顯示3。安全

  • 彷佛不爲人知:想要文件名展開時,把通配符以外的部分擴起來,例如"$DIR"/*,而不能全體擴起來"$DIR/*"bash

    同理,HOME目錄標記~也是不能擴起來。哪怕是雙引號。ide

  • 取得當前文件所在路徑,考慮到符號連接,能夠用這段代碼。函數

    支持一層符號連接。支持被包含調用(就是被source或者.命令調用)。

    thisDir=${BASH_SOURCE[0]%/*}
    if target=`readlink "${BASH_SOURCE[0]}"`; then
        if [[ $target == /* ]]; then     #absolute path target
            thisDir=${target%/*}
        elif [[ $target == */* ]]; then  #relative path target
            thisDir+=/${target%/*}
        fi
    fi
    #若是隻想獲得引用當前文件所在的目錄,不在意是否絕對路徑和空路徑(表示/),拿到此就夠了。要訪問該目錄下的東西就$thisDir/xx。
    
    if [[ ! $thisDir ]]; then
        thisDir=/
    else
        thisDir=$(cd $thisDir; pwd)    #若是返回相對路徑也行,那就不用這句了。
    fi
    echo $thisDir
  • 本身作的which_函數是4倍速於SOME_VAR=`type -p some_exe_name`

    #!/bin/bash
    
    IFS=: pathList=($PATH); unset IFS
    function which_ { x=""; for d in "${pathList[@]}"; do [[ -x $d/$1 ]] && { x=$d/$1; return 0; }; done; return 1; }
    
    echo 'x=`type -p aapt`'
    time {
        for i in {1..5000}; do
            x=`type -p aapt`
        done
    }
    echo $x
    
    echo which_
    time {
        for i in {1..5000}; do
            which_ aapt
        done
    }
    echo $x

    結果

    x=`type -p aapt`
    
    real	0m3.684s
    user	0m1.086s
    sys	0m2.382s
    /Users/q/Library/Android/sdk/build-tools/24.0.1/aapt
    which_
    
    real	0m0.788s
    user	0m0.686s
    sys	0m0.095s
    /Users/q/Library/Android/sdk/build-tools/24.0.1/aapt
  • 內部命令type -p是50倍速於which命令! 和which同樣也有-a選項,列出全部在$PATH裏的目標exe。

  • 文字分隔符IFS,能夠用來分隔$PATH裏的冒號

    IFS=":"; foo="12:34::78"; echo $foo

    結果是12 34 78

    IFS=":"; for p in $PATH; do echo $p; done; unset IFS

    結果是一個個的路徑。

    能夠生成一個數組

    IFS=":"; PATH_LIST=($PATH); unset IFS
    echo ${#PATH_LIST[@]}

    結果就是路徑個數。

  • 變量文字列替換

    例如${X/$Y}把$X裏含有$Y的部分刪除。

    • 變量替換有好幾種方式,吝嗇(/,#,%)或貪婪(//,##,%%),頭(#)或尾(%)。

    • 即便$X,$Y裏含有空格和/均可以

      X=/abc/OK
      Y=/abc/
      echo ${X/$Y}

      結果是OK。

    • 可是通配符會被針對$X範圍內自動展開,要當心。

      X=/abc/OK
      Y="*/"
      echo ${X/$Y}

      結果是OK。

      好笑的是,UNIX/Linux下的文件名稱裏是能夠包含這些通配符的, 一旦真有了,那就亂套了。Windows那邊是不容許有的。

  • 數組

    • array用法裏的下標*@是不同的

      如同"$*"會總體一個文字列而"$@"會按個數展開成若干文字列甚至含有空格的都不會亂, "${array[*]}""${array[@]}"也是相似的區別。

      array=("a b" c) 是含有2個元素的數組,${#array[@]}是2。

      for item in "${array[@]}"; do echo $item; done 會顯示正常,"a b"和c。

      可是for item in "${array[*]}"; do echo $item; done 就成了"a bc"

      for item in ${array[*]}; do echo $item; done 則成了三個了a和b和c

    • 數組的展開作得很理想"${array[@]}"當一個元素都沒有時,他不會產生任何輸出,連空文字列都沒有。

    • 數組添加array+=(newItem),合併array+=("${newArray[@]}")

  • bash裏的here document功能強大

    • <<<文字列表示輸入文字列,若是有空格什麼的得擴起來。 例如bash <<<"echo hi"結果爲hi。

    • <<\EOF裏的那個\表示here document裏的內容不要被展開,即無視$,*等東西。

    • <<-EOF裏的那個-支持TAB鎖進。

  • 命令行解析模版:

    function _agcc-dbg { echo "$@" >&2; }
    
    function main {
        local ARCH APIL STL FORCE  #若是不在function裏,那就換成ARCH=""之類的。
    
        _agcc-dbg "analysing args {"
        while [[ $# -gt 0 ]]; do
            _agcc-dbg "  \"$1\""
            case $1 in
                --arch    ) case $2 in [!-]*|"") ARCH=$2; _agcc-dbg "  =\"$2\""; shift;; esac;;
                --api     ) case $2 in [!-]*|"") APIL=$2; _agcc-dbg "  =\"$2\""; shift;; esac;;
                --stl     ) case $2 in [!-]*|"") STL=$2;  _agcc-dbg "  =\"$2\""; shift;; esac;;
                --force   ) FORCE=$1 ;;
                arm|arm64|x86|x86_64|mips|mips64) ARCH=$1 ;;
                min|max|0 ) APIL=$1 ;;
                gnustl|libc++|stlport ) STL=$1 ;;
                -c|-C     ) break ;; #stop parse due to the later args is command and its args
                -*        ) : ;; #skip unrelated option keyword
                *         ) [[ $1 -gt 0 ]] && APIL=$1 ;;
            esac
            shift
        done
        _agcc-dbg "}"
    
        #剩下的全部參數就是想要執行的外部命令和參數了,用"$@"來表明就好了。
        exec "$@"
    }
  • :表示什麼都不作的命令。

  • 檢測是否整數的判斷[[ $X != *[!0-9]* ]]

  • [[ ]]裏也能夠曖昧匹配,和case語句裏的匹配特性和同樣,可是不能寫多個 a|b|c這樣的不行。

  • [[ $X = +([0-9]之類的擴展匹配 ]]時須要extglob的shopt被設定上才能用。默認的非交互的bash裏是用不了的。

    bash的pattern match有些功能和shopt有關。看http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html 用shopt |grep on看看就知道了。

    checkwinsize   	on  #非交互bash裏沒有
    cmdhist        	on
    expand_aliases 	on  #非交互bash裏沒有
    extglob        	on  #非交互bash裏沒有,因此致使一些 $V == +([0-9]) 之類的整數匹配語法錯誤
    extquote       	on
    force_fignore  	on
    interactive_comments	on
    login_shell    	on
    progcomp       	on
    promptvars     	on
    sourcepath     	on
  • [[ ]]替代[ ]測試,避免種種意外。

    • 變量裏的空格不會被亂分割,用不着加引號了。

    • 可以模糊匹配。

      變量裏的通配符不會按照文件名展開,而是通配符是在比較目標變量內展開。

      X=2ab3
      [[ $X == [1-3]*3 ]] && echo OK

      結果OK。

    • [[ $X ]][[ ! $X ]]能夠直接判斷X變量有沒有值。

    • [[ $X == 1 && $Y == 2 || $Z ]]之類的&&||寫法是符合想象的。

    這些換成[ ]就不行了,$X會編程當前目錄下的全部文件名,語法都會出錯。

  • 變量default值:${1-arm}表示若是$1爲空那麼值爲arm。

    可是不能寫成${1:=arm},這是試圖對$1進行默認賦值。${X:=arm}是能夠的。

  • X=值很安全, 右邊不用加雙引號也OK,即便值裏含有空格和通配符,也不會被自動展開。

    不須要囉嗦的加上雙引號:X="...",這種寫法在裏面含有雙引號等時多重escape累死了。

    測試: X=*,而後echo $X確定會顯示出一堆當前目錄下的東西,被展開了。 可是X內部實際的確只保存了*一個字符,能夠用echo ${#X}來證明。 若是就想打印一個星號出來,那就echo "$X"

  • bash的job判斷很糟糕,or 和and並不如想象,要當心。

    ls non-exist-file || echo 1 && echo 2

    結果會是2,而不是常識的1+2。

  • { }之中的最後一個命令後面必定要加個;,{以後必定要有一個空格。真變態。

    最短的函數定義是function a { echo hi;}一個空格都不能省略。其實最後一個;}之間最好加個空格。

相關文章
相關標籤/搜索