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