很好的東西: 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;}
一個空格都不能省略。其實最後一個;
和}
之間最好加個空格。