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;}一个空格都不能省略。其实最后一个;}之间最好加个空格。

相关文章
相关标签/搜索