恩,這是由奇技淫巧組成的語言,沒有之一。奇技淫巧到,他的語法出如今你無數個靈光一現時刻~python
我:蔣哥你shell好厲害!mysql
蔣哥:恩git
我:要多久啊sql
蔣哥:(基於Java,python,js等)要一段時間docker
shell,殼,計算機命令終端,每一個unix體系的機器最原始都是使用這個與計算機操做系統進行交互的,相似的,windows操做系統下滿就是bat(批處理文件)。每次Linux系統啓動,登錄以後,都會默認啓動幾個這種命令終端,若是圖形界面有的話,通常會默認進入圖形界面。圖形界面之上,咱們也可使用Terminal這種模擬的命令終端,進行命令操做,這東西相似於windows的cmd。shell
對於編程這麼多年,變量很好理解,無非就是一個瞎幾把命名的一個單詞,賦值一個value嘛~真的嗎?奇技淫巧來了,請看下面數據庫
# ① var1=123 # ② var2='jicheng${var1}' # ③ var3="jicheng${var1}" # ④ var4=`pwd` # ⑤ var4 = `pwd` # ⑥ var4=$(pwd)
①shell變量沒類型,弱類型,萬物皆字符串,即便是這個,也是var1值是"123"express
②③單雙引號不同,單引號內部不轉義,寫啥是啥;雙引號會轉義,會替換變量值編程
④這種上引號是執行引用起來的字符串,因此被引用的要能被執行,結果賦值給等號左面的變量ubuntu
⑤這種是錯誤語法。賦值操做的等號兩邊不能有任何空格,這種有空格的,後面會將
⑥和④同樣
完了?遠遠還沒,來點晉級的:
# ① var4=${var1:-value} var4=${var1-value} # ② var5=${var1:=value} var5=${var1=value} # ③ var6=${var1:?value} var6=${var1?value} # ④ var7=${var1:+value} var7=${var1+value}
解說:不帶冒號表明var1是否爲未賦值,帶了表明var1是否爲未賦值或是空值
①var1未賦值(或空值)將"value"賦值給var4變量
②var1未賦值(或空值)將"value"賦值給var4,且一樣賦值給var1
③var1未賦值(或空值)將"value"做爲標準錯誤輸出,用於進行變量判空用的
④var1未賦值(或空值),什麼都不作,不然value代替var1的值,賦值給var7,var1的值不變
一個真正的shell腳本在執行過程當中,會有一些特殊的變量,這個對理解shell程序相當重要,來戰:
#!/bin/bash # shell_test.sh腳本 echo $0 echo $(basename $0) echo $1 $2 echo $# echo $* echo "$*" echo $@ echo "$@"
$0:
獲取執行腳本本身的文件名,執行的輸入全字符串,例如./shell.sh、/etc/profile_test.sh,若是想單純獲取名字,要用:$(basename $0)
$1,$2,$3……..$n這種
回去執行名稱後面對應的輸入參數,$1表明第一個,$n表明第n個
$#
獲取輸入參數一共有多少個
$*與$@
不加引號,兩個同樣:都是將入參使用IFS定義的分隔符進行拆分;加了就有區別:$*會把全部入參當作一個總體的字符串,而$@會將使用雙引號的入參當作一個,不進行IFS分隔符拆分操做。下面代碼是兩個變量的對比試驗:
#!/bin/bash # 對$*與$@作對比試驗 # 將帶引號的入參進行IFS分割拆分 for i in $*; do echo $i done # 恩,這就是一個大的字符串 for i in "$*"; do echo $i done # 將帶引號的入參進行IFS分割拆分 for i in $@; do echo $i done # 不將帶引號的入參進行IFS分割拆分 for i in "$@"; do echo $i done
每次運行shell腳本,或者咱們開啓一個Terminal,或者咱們遠程登錄一個命令終端,其實都是有預先設置好的變量存在的,這個就叫:環境變量。若是是全局的環境變量,就是說,每一個用戶登陸都能看到的,能夠說是全局變量,相似於windows裏面的系統變量的概念;若是環境變量只是當前用戶可以看到的,那就是局部環境變量,相似於windows裏面的環境變量的概念。內部有幾個很關鍵的腳本文件,專門用來設置全局與局部變量的,大體總結下:
下面是profile的源代碼:
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1)) # and Bourne compatible shells (bash(1), ksh(1), ash(1), ...). if [ "`id -u`" -eq 0 ]; then # id -u 顯示登錄用戶id,0是root用戶 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" else PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" fi export PATH # 下面的判斷語法是否是很熟悉呢? # 這裏主要進行PS1這個環境變量的設置,主要影響交互式命令號行頭標示符 if [ "${PS1-}" ]; then if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then if [ -f /etc/bash.bashrc ]; then # 到這裏就是判斷當前是否是不是使用sh且存在bash.bashrc文件 . /etc/bash.bashrc fi else # sh模式(不是bash模式),就是所謂的POSIX兼容模式 if [ "`id -u`" -eq 0 ]; then PS1='# ' else PS1='$ ' fi fi fi if [ -d /etc/profile.d ]; then # 第一個判斷文件夾是否存在 for i in /etc/profile.d/*.sh; do # 遍歷文件夾中的每一個文件 if [ -r $i ]; then # 判斷單個文件是否存在,執行 . $i fi done unset i fi
下面針對用戶環境變量設置是按順序,找到的就會執行,沒找到就不執行:
通常狀況下,會只存在一個。例如,Debian系統下面,用戶目錄下面只有.profile。但是內部又調用執行類另一個同目錄的文件:.bashrc。下面是真是的源碼:
# ~/.profile: executed by Bourne-compatible login shells. if [ "$BASH" ]; then # 若是BASH變量存在就執行這個代碼塊 if [ -f ~/.bashrc ]; then # 若是.bashrc這個文件存在在用戶目錄中,就執行這個代碼塊 . ~/.bashrc # 這種的另外一種寫法是:source ~/.bashrc fi fi mesg n || true
# ~/.bashrc: executed by bash(1) for non-login shells. # 這裏都註釋掉了,認真閱讀可見,咱們平時經常使用的命令簡寫都出自這裏,只不過這個系統定製性的給去掉了 # Note: PS1 and umask are already set in /etc/profile. You should not # need this unless you want different defaults for root. # PS1='${debian_chroot:+($debian_chroot)}\h:\w\$ ' # umask 022 # You may uncomment the following lines if you want `ls' to be colorized: # export LS_OPTIONS='--color=auto' # eval "`dircolors`" # alias ls='ls $LS_OPTIONS' # alias ll='ls $LS_OPTIONS -l' # alias l='ls $LS_OPTIONS -lA' # # Some more alias to avoid making mistakes: # alias rm='rm -i' # alias cp='cp -i' # alias mv='mv -i'
對於平常的使用,最多見的莫過於字符串拼接,與數字的運算,下面分別來講說這兩方面
#!/bin/bash str1=hello str2=shell str3=world echo $str1$'\t'$str2$'\t'$str3 # 輸出爲:hello shell world
$'string'這種類型的值會被特殊解析。這種值,內部使用反斜槓加一個字符,都會按照標準c的模式進行轉義。若是存在這種反斜槓轉義序列, 映射關係以下: /a 警告(鈴聲) /b 退格 /e 一個轉義字符 /f 換頁 /n 換行 /r 回車 /t 水平製表符 /v 垂直製表符 // 反斜槓 /' 單引號 /nnn 八進制 /xHH 十六進制 /cx 控制x字符(沒弄明白這個何時用)
shell自己就是萬物皆字符串,因此對於純數學計算支持的不是很好。大致上分兩大類:整數運算與浮點數運算。實踐的方式有三種,前兩種是整數運算,最後一種是浮點數運算
#!/bin/bash # An example of using the expr command var1=10 var2=20 var3=$(expr $var2 / $var1) echo The result1 is $var3 var3=$(expr $var2 \* $var1) echo The result2 is $var3
這東西很差使用,並且是很是。其中還會支持以下的一些操做:
這東西,若是是取結果值,賦值給其餘變量的話,通過實際的測驗,還有一些貓膩,請仔細看下面代碼與註釋:
#!/bin/bash # 測試expr取值操做 expr $var \| 3 #若是是沒被賦值參與了運算的,這時候會報錯 $var= expr $var \| 3 #這種被賦了個空值,也會報錯 $var=1 expr $var \| 3 #這種纔不會報錯,按照正常邏輯返回值:1 $var= expr "$var" \| 3 #這種也不會報錯,直接取了var的空值,結果爲:3 expr 3 | 2 #不轉義「或」符號報錯,shell會當作管道符號處理,而2並非命令 expr 4\*3 #這種直接返回結果:4*3(字符串) expr 4\* 3 #這種語法錯誤,操做符的兩邊必需要有空格
可見shell下面的算術運算操做並不容易,很是多的小細節,恩就是所謂的「奇技淫巧」!
中括號主要是爲了取代expr而出現的,主要也是用於整數的算術運算與邏輯運算,而且可以方便的取值操做。畢竟,使用expr有太多奇技淫巧,太多要注意的語法細節了,而中括號,偏偏能很好的解決這些。下面是一些語法舉例:
#!/bin/bash # 中括號算術運算舉例 [4*4] #單獨這樣會有語法錯誤,由於中括號語法要配合$來使用,報錯信息:[4*4]:未找到命令 [ 4*4 ] #這種其實沒有語法錯誤,中括號裏面兩邊有了空格這種,屬於判斷語句,下面會介紹到 [4 * 4] #這種操做符有了空格,會被命令解釋器拆分紅三個命令:[四、*、4],而[4並非命令,因此報錯 $[4*6] #這種表達式自己是沒問題的,可以求結果,但是結果求出來了shell會運行結果,顯然24不是命令,報錯 var=$[3 *4] #這種是最正確的,操做符左右不用擔憂空格、也不用擔憂轉義問題,求結果,並賦值操做
仔細閱讀上面註釋,就能夠了。是否是感受shell很是死扣一些細節?這個腳本語言就這個德行!
恩,最後了,一步步闖關以後,這東西是「公主」!最好控制的東西(就是奇技淫巧少)。好控制不表明好用,來看看bc兩種模式
bash計算器其實是一種編程語言,它容許在命令行中輸入浮點表達式,而後解釋並計算該 表達式,最後返回結果。bash計算器可以識別:
下面是我一頓瞎幾把搞的代碼:
jicheng:~/Project/shell_test$ bc -q #q是不顯示軟件介紹 34.5 23*34.645645 796.849835 234*3-(3/ 234)#支持混合運算 702 3/ 234 0 3.0/ 234.023 0 scale= 6 #默認是0,不設置,小於1的除法結果顯示0 3.0/ 234.023 .012819 3/ 234 .012820 var1=10 #內部支持變量 var1 * 4 40 var2 = var1 / 5 print var2 2 quit jicheng:~/Project/shell_test$
基本語法爲:variable=$(echo "options; expression" | bc)
#!/bin/bash var1=100 var2=45 var3=$(echo "scale=4; $var1 / $var2" | bc) # 看到如何設置精確值 echo The answer for this is $var3
這兩個話題也是一大難。哎~難點在於不少不少的細節,仍是那樣,難在正所謂的"奇技淫巧",咱們分開2小節來說:
對於一個計算機語言來講,輸入,無非就是:用戶交互式輸入與文件內容的輸入。Shell裏面也同樣。針對用戶的輸入,能夠從命令傳入,也可實時讀取用戶的外設輸入。而針對這些個輸入,shell會有相應的讀取與保存方式,下面分開來介紹
在執行命令時候,默認以空格分割,緊接着在命令後面進行傳入的連續字符串。分割方式是空格,若是入參自己帶空格,要使用引號或者雙引號,進行引用包裹
#!/bin/bash # ./shell_test var1 var2 var3 #正確獲取文件名的真實寫法 echo `basename $0` echo $1 echo $2 echo $3 # 一共有多少個入參 echo $# # 最後一個入參 echo ${!#}
大部分知識都在上面變量小節介紹過了,上面關鍵的是最後兩行代碼:
有時候,咱們會動態獲取輸入參數,並循環作處理,例以下面的方式:
#!/bin/bash # shell_test.sh文件 count=1 for var in "$@" do echo "Parameter #$count: $var" count=$[ $count + 1 ] done # 運行:./shell_test var1 var2 # 結果: # Parameter #1: var1 # Parameter #2: var2
很簡單。再高一個難度:若是咱們想對入參進行分類,區分配置選項與輸入參數兩種,例如咱們常用的
ls -al
不就是有配置選項al。看下面咱們怎麼用實際的代碼進行實現:
#!/bin/bash # shell_test.sh文件 while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option";; -b) echo "Found the -b option";; -c) echo "Found the -c option";; *) echo "$1 is not an option";; esac shift done <<COMMENT 輸入 /shell_test.sh -a -c -b -d 結果: Found the -a option Found the -c option Found the -b option -d is not an option COMMENT
shift是shell內部的一個命令,能夠左移一個輸入參數,被移動的入參,將會消失,例如,入參有var一、var2,shift以後,入參只有var2。shift能夠有參數,後面加上一個數字,表示要左移多少個參數。上面的代碼用到告終構化的語句,後面章節會進行介紹。接下來咱們再高一個級別:我不只僅想要配置選項的入參,我還想要配置參數的入參,那咱們怎麼定義呢?針對輸入方式,咱們能夠用一個特殊字符來隔離選項與參數,例如'—',看下面:
#!/bin/bash # shell_test.sh while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option";; -b) echo "Found the -b option";; -c) echo "Found the -c option";; # 這裏作了特殊處理:shift掉了--入參,並結束while循環 --) shift break ;; *) echo "$1 is not an option";; esac shift done count=1 for var in "$@" do echo "Parameter #$count: $var" count=$[ $count + 1 ] done <<COMMENT 輸入:./shell_test.sh -a -b -c -- var1 var2 var3 輸出: Found the -a option Found the -b option Found the -c option Parameter #1: var1 Parameter #2: var2 Parameter #3: var3 COMMENT
已經有點規模了,哈哈。接下來咱們還想進一步,ls -al
相似於這種,人家成熟的命令但是能夠合併配置選項的,但是上面的代碼並不支持。接下來就是最終的解決方案,要用到一個很好的命令:getopts。下面是代碼,邊寫邊解說:
#!/bin/bash while getopts :ab:c opt do case "$opt" in a) echo "Found this -a option";; b) echo "Found this -b option,with value $OPTARG";; c) echo "Found this -c option";; *) echo "Unknow";; esac done shift $[ $OPTIND -1 ] count=1 for param in "$@" do echo "Parameter $count: $param" count=$[ $count+1 ] done <<COMMENT 輸入:./shell_test -ab var1 -c var2 var3 輸出: Found this -a option Found this -b option,with value var1 Found this -c option Parameter 1: var2 Parameter 2: var3 COMMENT
一波解釋:
至此咱們對於命令傳參式輸入就全介紹完了,下面開始說用戶交互式輸入
這種比較簡單一些,就是用read這個命令一頓瞎幾把搞~直接上代碼,直接解釋:
#!/bin/bash # 最基本的read,阻塞式的輸入,用echo的n(不換行)參數配合打印提示行 echo -n "Enter your name: " read name echo "Hello $name, welcome to my program. " # 使用read的p參數,直接打印提示航 read -p "Please enter your age: " age days=$[ $age * 365 ] echo "That makes you over $days days old! " # 使用read的t參數,來進行超時控制,單位是秒 if read -t 5 -p "Please enter your name: " name then echo "Hello $name, welcome to my script" else echo "Sorry, too slow! " fi # 使用read的s參數,能夠隱藏輸入的字符,好比密碼輸入 read -s -p "Enter your password: " pass echo "Is your password really $pass? "
文件中的輸入,主要仍是運用read這個命令,也是直接代碼:
#!/bin/bash # reading data from a file # count=1 # test是一個文本文件 cat test | while read line do echo "Line $count: $line" count=$[ $count + 1] done echo "Finished processing the file"
line是記錄了每一行的記錄,咱們能夠根據需求,繼續對每行的數據進行切割處理
在shell中,輸出永遠和重定向脫不開干係,由於在shell中不管是輸出到屏幕(標準輸出)或是輸出到文件,都是要靠重定向標準輸出來 實現的,因此掌握各類重定向的方式,很關鍵,一樣,這裏也是好幾種「奇技淫巧」的方式進行重定向。下面我分別說說幾個方面。
在運行shell腳本的時候,會有一系列的文件描述符,用數字表示,最多有9個,最多見的就是系統設定好的前三個:
咱們能夠重定向這幾個,同時也能夠本身建立新的文件描述符:
#!/bin/bash # 默認狀況的echo,直接輸出到標準輸出 echo "echo 2 STDOUT" # 咱們能夠進行重定向標準輸出,這樣就會輸出到具體的文件當中去 echo "echo 2 other" >test.out ## 雙大於號的輸出表示追加到一個文件,不是覆蓋 echo "echo 2 other" >>test.out # 下面的jiad是沒有的目錄,標準錯誤會輸出到屏幕 ls /jiad # 對標準錯誤輸出進行重定向,直接在大於號前面加數字 ls /jiad 2>test.out # 全局性永久重定向,使用exec命令原理是啓動一個新的shell而後進行重定向 exec 2>test.out ls /jiad #這種錯誤會直接輸出到test.out文件,由於標準錯誤全局性的重定向了 # 這種就是自定義文件描述符3,而後重定向到test.out文件 exec 3>test.out # 引用文件描述符的方式,這樣輸出的結果就覆蓋到了test.out文件裏面了 echo "echo 2 other" >&3
上面主要的語法都已經列出來,仔細閱讀註釋就能夠了。另外,這地方對重定向的箭頭左右是否有空格,要求不是特別的嚴格,有沒有功能都不會受影響,請放心使用。
當咱們使用exec命令永久性的重定向了標準輸出的話,如何再重定向回來本來的呢?也很簡單,就如咱們最開始學習編程時候學的「三段式」交換數字同樣,先暫存,再操做,最後再反賦值就能夠了,就以下面:
#!/bin/bash exec 3 >&1 exec 1 >test.out echo "temp save file description" # 看到沒?直接把1再重定向會3,3裏面,最開始是重定向到標準輸出的 exec 1 >&3
輸入的文件 標示符是0,重定向使用小於號,簡單的一個重定向代碼以下:
#!/bin/bash # 0和符合之間不能有空格,其實他們是一體的,表示:0文件描述符輸入重定向 exec 0< out # 這種狀況,cat並不會進行交互式輸入了,而會從out文件進行輸入 cat
一樣,咱們能夠經過暫存的方式進行恢復重定向的標準輸入
#!/bin/bash # 下面的小於號左右不能有空格存在,不然語法報錯,&符號與前面不能有空格 exec 3<&0 exec 0<out # 這裏的cat的輸入已經變成了out文件 cat # 這個命令能夠查詢0,1,2,3幾個文件描述符的指向文件 lsof -a -p $$ -d 0,1,2,3 # 恢復標準輸入的文件描述符 exec 0<&3 lsof -a -p $$ -d 0,1,2,3 # 這個時候會變成交互式輸入 cat
在輸入重定向這裏,有個"奇技淫巧",就是咱們可以腳本中動態設置標準輸入(重定向),而不用非得使用原生的標準輸入或是文件輸入,語法以下:
command << delimiter document delimiter
具體咱們舉一個例子:
#!/bin/bash # read file and create INSERT statements for MySQL outfile='members.sql' IFS=',' while read lname fname address city state zip do # 注意這個地方 cat >> $outfile << EOF INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('$lname', '$fname', '$address', '$city', '$state', '$zip'); EOF done < ${1}
上面的cat,實際上是直接在命令行執行cat這種模式的,只不過在執行的時候,重定向了兩個東西:
頗有意思,這種方式,很普遍被運用,例如:shell腳本對mysql數據庫執行一條sql語句
說到了最後,這一章說完,幾乎shell的語法部門就結束了。剩下的,就是深刻大海般的」命令海「!這些命令,有系統自帶的,也有咱們本身安裝的工具帶的命令,或是咱們安裝的軟件帶來的命令,例如git、docker等。針對結構化的問題,也算是放輕鬆了,由於結構化的語法,是平時咱們最最多見的了。
這兩個東西,在任何計算機語言體系中,可謂是老生常談了。很少說,下面是基本語法,有兩種模式:
# 第一種模式 if command then command1 command2 ...... fi # 第二種模式 if command; then command1 command2 ...... fi # 多級別的ifelse if command1 then commands elif command2 then more commands else more commands fi
特別注意點:shell中沒有所謂的判斷真(true)假(false)一說,這裏的if語句中的判斷語句是一個具體的命令(command)。根據命令的執行退出的狀態值來判斷是否要執行if裏面的代碼塊: 若是這個命令正確執行,那退出值爲0,if代碼塊就被執行;若是命令執行過程當中發生錯誤,退出值就不爲0,那if代碼塊就不被執行。這就是shell中的語法。後面的while、for、util等都是這種規則
下面就是基本的shell中if語句的代碼:
#!/bin/bash # Testing nested ifs - use elif & else # testuser=NoSuchUser if grep $testuser /etc/passwd then echo "The user $testuser exists on this system." elif ls -d /home/$testuser then echo "The user $testuser does not exist on this system." echo "However, $testuser has a directory." else echo "The user $testuser does not exist on this system." echo "And, $testuser does not have a directory." fi
雖然ifelse的判斷語句是運行一個命令,而後根據退出值來判斷的,可是能不能讓咱們仍是像以往那樣,根據語句的真假來判斷是否執行語句塊呢?恩,test命令就是解決這個問題的:
if test condition then commands fi
#!/bin/bash my_var='jicheng' if test $my_var then # 這個會被執行,由於test命令會讓退出值爲0 echo "myvar" fi my_null_var="" if test then # 空的test的退出值不爲0,因此這個地方不會被執行 echo "1" elif test my_null_var then # test空串也是會退出值不爲0的,因此這裏也不會執行 echo "2" else echo "3" fi
固然,shell中不會傻呵呵讓你一直寫test的,提供了一個替換語法:
# 注意這裏:中括號內部的condition兩邊必需要有空格,不然語法有錯,上面立的flag,在這裏能夠拔下來了 if [ condition ] then commands fi
針對性的,test的語法,能夠對三種類型進行條件判斷下面分三個小節
因爲shell中萬物皆字符串,因此對於數值的比較,要使用關鍵字進行,不難,下面就是:
下面是簡單的例子:
#!/bin/bash value1=10 value2=11 # if [ $value1 -gt 5 ] then echo "The test value $value1 is greater than 5" fi # if [ $value1 -eq $value2 ] then echo "The values are equal" else echo "The values are different" fi
注意shell中只能處理整數,對於浮點數的test,會報錯。不支持
其實也不難,主要注意和sort的區別。下面是基礎的一些字符串比較表達式:
注意點有幾個:
[ "test" \> "Test" ]
下面是簡單的測試代碼:
#!/bin/bash # testing string sort order val1=Testing val2=testing # if [ $val1 \> $val2 ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi
最後一類比較測試頗有多是shell編程中最爲強大、也是用得最多的比較形式。它容許你測 試Linux文件系統上文件和目錄的狀態:
#!/bin/bash if [ -d $HOME ] && [ -w $HOME/testing ] then echo "The file exists and you can write to it" else echo "I cannot write to the file" fi
雙小括號模式是(用於算術運算比較):
(( expression ))
支持:var++、var--、++var、--var、!(非)、~(位求反)、**(冪運算)、<<(左移)、>>(右移)、&(位與)、|(位或)、&&(邏輯與)、||(邏輯或)。另外這種模式下大於小於號不用轉義!
雙中括號的模式是(用於字符串比較):
[[ expression ]]
雙方括號裏的expression使用了test命令中採用的標準字符串比較。但它提供了test命 令未提供的另外一個特性——模式匹配(pattern matching)。
#!/bin/bash if [[ $USER == r* ]] then echo "Hello $USER" else echo "Sorry, I do not know you" fi
多說兩句:在這裏,對於這兩個東西,能夠玩的花樣有點多,平常使用的也會總去使用這兩個運算符的花樣,這個我在後面單獨開文章細講」奇技淫巧「!
通常高級靜態語言中,都有switch的語法,shell中也有。不過這裏的使用方式,有點"詭異":
case variable in pattern1 | pattern2) commands1;; pattern3) commands2;; *) default commands;; esac
和Java中不一樣,這裏每一個匹配了但括號裏面的模式並執行了command以後,就結束case語句了,並且使用兩個;符號結尾。而Java中不使用break的話,會一直匹配下面全部的模式並執行裏面代碼塊。
#!/bin/bash # using the case command # case $USER in rich | barbara) echo "Welcome, $USER" echo "Please enjoy your visit";; testing) echo "Special testing account";; jessica) echo "Do not forget to log off when you're done";; *) echo "Sorry, you are not allowed here";; esac <<COMMENT 輸出: Welcome, rich Please enjoy your visit COMMENT
for語句在shell中,有兩種方式,一種是原生的,一種是C語言風格的。可是C風格的for語句,在一些bash中並非很支持(ubuntu16中的dash就不支持),因此我看,大部分仍是使用原生的for語句爲主,咱們這裏就先不講C風格的for。原生的for,在一些小細節上面仍是要注意的,下面是基本的語法:
for var in list do commands done
#!/bin/bash for var in I don't know if this'll work do echo "$var" done
結果是:
I
dont know if thisll
work
顯然不符合咱們的預期,由於shell把兩個引號中間的部分當作一個字符串了,有兩種解決方法:
#!/bin/bash # 一種進行轉義,一種使用雙引號括起來 for var in I don \'t know if "this'll" work do echo "$var" done
#!/bin/bash for var in Nevada New Hampshire New Mexico New York do echo "Now going to $var" done
結果是:
Now going to Nevada
Now going to New
Now going to Hampshire
Now going to New
Now going to Mexico
Now going to New
Now going to York
Now going to North
Now going to Carolina
顯然就不符合。咱們可使用雙引號括起來:
#!/bin/bash for var in Nevada "New Hampshire" "New Mexico" "New York" do echo "Now going to $var" done
#!/bin/bash # reading values from a file file="states" IFS=$'\n' for state in $(cat $file) do echo "Visit beautiful $state" done
這樣,對於文件中的分割,只會使用換行符
#!/bin/bash for file in /home/rich/test/* do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" fi done
注意使用雙引號括起來了文件名的引用變量,是由於有可能文件名有空格,若是不括起來,語法就會有錯誤了!
經歷了前面的if與for的歷練,對於while這裏的語法相對來講就沒有那麼難理解了:
while test command do other commands done
簡單的例子:
#!/bin/bash var1=10 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done
這個和while的邏輯相反:while是知道test退出碼爲非零的時候,結束循環,而這個是當test循環退出碼爲零的時候結束循環,語法也是相似:
until test command do other commands done
例子不舉了
到此幾乎最最基本的shell語法就差很少都講了。剩下的,就是如"汪洋"的命令大軍了。哪怕是這些基礎的語法,我都感受,是由命令組成的,這就是shell編程,瘋狂的奇技淫巧~接下來我會短平快的寫幾個小案例和shell中經常使用的命令,例如awk,sed,find等,如如有具體的語法」靈光一現「,都會update到本篇幅中,恩就這樣。