LINUX Shell特殊字元的表示方法 # 注釋1. 表示注釋 #注釋2. 在引號中間和\#等表示#本身3.echo ${PATH#*:} # 參數替換,不是一個注釋4.echo $(( 2#101011 )) # 數制轉換,不是一個注釋echo "The # here does not begin a comment."echo 'The # here does not begin a comment.'echo The \# here does not begin a comment.echo The # 這裡開始一個注釋.echo ${PATH#*:} # 參數替換, 不是一個注釋.echo $(( 2#101011 )) # 數制轉換, 不是一個注釋.這裡特別要注意第四個,一定要有空格,否則不認同是注釋; 分隔1.命令分隔,在一行中寫多個命令 echo "aa" ; echo "bb"2.在條件中的if和then如果放在同一行,也用;分隔 ;; case條件的結束1.命令分隔,在一行中寫多個命令 echo "aa" ; echo "bb"2.在條件中的if和then如果放在同一行,也用;分隔echo hello; echo thereif [ -x "$filename" ]; then # 注意: "if"和"then"需要分隔. echo "File $filename exists."; cp $filename $filename.bakelseecho "File $filename not found."; touch $filenamefi; echo "File test complete." . 命令相當於1.命令:source2.檔案名稱的首碼,隱藏檔案3.目錄:.目前的目錄,..父目錄4.Regex:匹配任意單個字元首先,先舉例說明一下"."作為source使用的執行個體#!/bin/bash. data-file # 載入一個資料檔案.# 與"source data-file"效果相同, 但是更具可移植性.# 檔案"data-file"必須存在於當前工作目錄, 因為這個檔案是使用'basename'來引用的. echo "variable1 = $variable1"echo "variable3 = $variable3"let "sum = $variable2 + $variable4"echo "sum = $sum"exit 0上面是編寫的include_file指令碼,通過 . data-file引入,相當於c語言中的include data-file,我們看看data-file的內容# 這是需要被指令碼載入的資料檔案.# 這種檔案可以包含變數, 函數, 等等.# 在指令碼中可以通過'source'或者'.'命令來載入. # 讓我們初始化一些變數.variable1=22variable2=474variable3=5variable4=97message1="Hello, how are you?"message2="Enough for now. Goodbye."接下來我們看看指令碼的執行結果:root@ubuntu:~/resource/study/shell_study# chmod 777 include_file root@ubuntu:~/resource/study/shell_study# lsclear_log data-file include_file show_selfroot@ubuntu:~/resource/study/shell_study# ./include_file variable1 = 22variable3 = 5sum = 571上面的結果已經很有力的說明了我們想要的結論.作為隱藏檔案時,建立隱藏檔案的方法:touch .data-file .作為匹配字元說明如下:ab. 可以表示ab+任一字元,處理換行,並且必須是一個字元ab.不能表示ab "" 部分引用 支援萬用字元擴充"STRING"將會阻止(解釋)STRING中大部分特殊的字元 ' ‘ 全引用,不進行萬用字元擴充'STRING'將會阻止STRING中所有特殊字元的解釋. 這是一種比使用"更強烈的形式 \ 轉義\X將會"轉義"字元X. 這等價於"X", 也等價於'X'. \通常用來轉義"和', 這樣雙引號和單引號就不會被解釋成特殊含義了. / 目錄分隔字元分隔檔案名稱不同的部分(比如 /home/bozo/projects/Makefile).也可以用來作為除法算術操作符. , 多個命令都被執行,但返回最後一個逗號操作符連結了一系列的算術操作. 雖然裡邊所有的內容都被運行了,但只有最後一項被返回.let "t2 = ((a = 9, 15 / 3))" # Set "a = 9" and "t2 = 15 / 3"逗號之前會運算,但是只有最後一項被返回 ` 後置引用`command`結構可以將命令的輸出賦值到一個變數中去. cd $LOG_DIRif [ `pwd` != "$LOG_DIR" ]thenecho "Can't change to $LOG_DIR"exit $E_XCDfi這裡例子是最有力的的說明,在上一章中只不過沒有到這個方法,這裡pwd命令會返回當前路徑,然後與LOG_DIR進行比較,同樣你可以定義一個變數儲存pwd返回的內容,比如:path=`pwd` : 操作符1.空操作,等價於"NOP" (no op, 一個什麼也不乾的命令). 1 : 2 echo $? # 02.死迴圈: while :,可以被認為與shell的內建命令,與true作用相同. while : do operation-1 operation-2 ... operation-n done # 與下邊相同: # while true # do # ... # done3.在if/then中表示什麼都不做,引出分支if conditionthen : # 什麼都不做,引出分支. elsetake-some-actionfi 4.設定預設參數 : ${username=`whoami`}: ${username=`whoami`}# ${username=`whoami`} 如果沒有開頭的":"的話, 將會給出一個錯誤, 除非"username"是一個命令或者內建命令 5.變數替換 : ${HOSTNAME?} ${USER?} ${MAIL?}: ${HOSTNAME?} ${USER?} ${MAIL?}# 如果一個或多個必要的環境變數沒被設定的話, 就列印錯誤資訊. 6.在和 > (重新導向操作符)結合使用時,把一個檔案截斷到0 長度,沒有修改它的許可權;如果檔案在之前並不存在,那麼就建立它.如: : > data.xxx #檔案"data.xxx"現在被清空了. 與 cat /dev/null >data.xxx 的作用相同 然而,這不會產生一個新的進程,因為":"是一個內建命令.在和>>重新導向操作符結合使用時,將不會對想要附加的檔案產生任何影響.如果檔案不存在,將建立.7.可能用來作為注釋行, 雖然我們不推薦這麼做. 使用#來注釋的話, 將關閉剩餘行的錯誤檢查, 所以可以在注釋行中寫任何東西. 然而, 使用:的話將不會這樣. : This is a comment that generates an error, ( if [ $x -eq 3] ).8.":"還用來在/etc/passwd和$PATH變數中做分隔字元.bash$ echo $PATH/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games * 匹配0個或多個字元;數學乘法;**冪運算root@ubuntu:~/resource/study/shell_study# lsclear_log data-file include_file show_selfroot@ubuntu:~/resource/study/shell_study# echo *clear_log data-file include_file show_self ? 匹配任意一個字元;但在((a>b?a:b))表示c語言中的三目運算 (( t = a<45?7:11 )) # C語言風格的三元操作. $ 字元1.取變數的值 echo $PATHvar1=5var2=23skidooecho $var1 # 5echo $var2 # 23skidoo2.Regex中表示行的結尾在Regex中, "$"表示行結束符,先分析一下下面的例子吧root@ubuntu:~/resource/study/shell_study# echo slfjalj$fdjglslfjalj3.${} 參數替換 ${PAHT}#!/bin/bash 2 # param-sub.sh 3 4 # 一個變數是否被聲明或設定, 5 #+ 將會影響這個變數是否使用預設值, 6 #+ 即使這個變數值為空白(null). 7 8 username0= 9 echo "username0 has been declared, but is set to null." 10 echo "username0 = ${username0-`whoami`}"這裡定義了username0且初始化是null,所以這裡不會有輸出,這裡的“-”相當於“=” 11 # 不會有輸出. 12 13 echo 14 15 echo username1 has not been declared. 16 echo "username1 = ${username1-`whoami`}"這裡username1在上面沒有定義並初始化為null,所以會顯示 17 # 將會輸出預設值. 18 19 username2= 20 echo "username2 has been declared, but is set to null." 21 echo "username2 = ${username2:-`whoami`}"這裡上面初始化了username2並初始化為null,但是這裡有個“:” 22 # ^ 23 # 會輸出, 因為:-會比-多一個條件測試. 24 # 可以與上邊的例子比較一下. 25 26 27 # 28 29 # 再來一個: 30 31 variable= 32 # 變數已經被聲明, 但是設為空白值. 33 34 echo "${variable-0}" # (沒有輸出) 35 echo "${variable:-1}" # 1 36 # ^ 37 38 unset variable 39 40 echo "${variable-2}" # 2 41 echo "${variable:-3}" # 3 42 43 exit 0我們也看看他的執行結果:root@ubuntu:~/resource/study/shell_study# chmod 777 para_sub root@ubuntu:~/resource/study/shell_study# lsclear_log data-file include_file para_sub show_selfroot@ubuntu:~/resource/study/shell_study# ./para_sub username0 has been declared, but is set to null.username0 = username1 has not been declared.username1 = rootusername2 has been declared, but is set to null.username2 = root ^ 1234.$* 所有參數5.$# 參數個數6.$$ 進程的ID7.$? 進程的返回狀態 ( )字元1.命令組,在一個子Shell中運行 (a=3;echo $a) 其中定義的變數在後面不可用在括弧中的變數,由於是在子shell中,所以對於指令碼剩下的部分是停用. 父進程, 也就是指令碼本身, 將不能夠讀取在子進程中建立的變數, 也就是在子shell中建立的變數. 1 a=123 2 ( a=321; ) 3 4 echo "a = $a" # a = 123 5 # 在圓括弧中a變數, 更像是一個局部變數. 2.數組初始化: array=(a,b,c)大括弧擴充 1 cat {file1,file2,file3} > combined_file 2 # 把file1, file2, file3串連在一起, 並且重新導向到combined_file中. 3 4 5 cp file22.{txt,backup} 6 # 拷貝"file22.txt"到"file22.b { } 代碼塊,即一個匿名函數,但其中定義的變數在後面依然可用#!/bin/bash# 從/etc/fstab中讀行.File=/etc/fstab{read line1read line2read line3} < $File echo "First line in $File is:"echo "$line1"echoecho "Second line in $File is:"echo "$line2"echoecho "third line in $File is:"echo "$line3"exit 0執行結果:root@ubuntu:~/resource/study/shell_study# ./test1 First line in /etc/fstab is:# /etc/fstab: static file system information. Second line in /etc/fstab is:# third line in /etc/fstab is:# Use 'blkid -o value -s UUID' to print the universally unique identifier接下來看一個例子:#!/bin/bash { echo "Just for a test:"echo `pwd`echo "Test end"} > "test-context" # 把代碼塊中的所有輸出都重新導向到檔案中. echo "Results of rpm test in test-context"exit 0看看運行結果:root@ubuntu:~/resource/study/shell_study# chmod 777 test2 root@ubuntu:~/resource/study/shell_study# ./test2 Results of rpm test in test-contextroot@ubuntu:~/resource/study/shell_study# lsclear_log include_file show_self test2data-file para_sub test1 test-contextroot@ubuntu:~/resource/study/shell_study# cat test-context Just for a test:/root/resource/study/shell_studyTest end{ } \; 用在find的-exec中 $find -name *.txt -exec cat {} \;[ ]1.測試 [-z $1]2.數組元素 a[1]='test'3.[[]]表示測試 使用[[ ... ]]條件判斷結構, 而不是[ ... ], 能夠防止指令碼中的許多邏輯錯誤. 比如, &&, ||, <, 和> 操作符能夠正常存在於[[ ]]條件判斷結構中, 但是如果出現在[ ]結構中的話, 會報錯.4.(( ))數學運算5.在Regex中表示範圍 [a-z] < << > 重新導向和進程替換 ls -al > a.txtscriptname >filename 重新導向scriptname的輸出到檔案filename中. 如果filename存在的話, 那麼將會被覆蓋.command &>filename 重新導向command的stdout和stderr到filename中.command >&2 重新導向command的stdout到stderr中.scriptname >>filename 把scriptname的輸出追加到檔案filename中. 如果filename不存在的話, 將會被建立.[i]<>filename 開啟檔案filename用來讀寫, 並且分配檔案描述符i給這個檔案. 如果filename不存在, 這個檔案將會被建立. > < 還用在ASCII比較 if [[ "$veg1" < "$veg2" ]]\<,\> Regex中的單詞邊界.如:bash$grep '\<the\>' textfile | 管道分析前邊命令的輸出, 並將輸出作為後邊命令的輸入. 這是一種產生命令鏈的好方法.echo ls -l | sh # 傳遞"echo ls -l"的輸出到shell中,與一個簡單的"ls -l"結果相同.cat *.lst | sort | uniq # 合并和排序所有的".lst"檔案, 然後刪除所有重複的行. 管道是進程間通訊的一個典型辦法, 將一個進程的stdout放到另一個進程的stdin中. 標準的方法是將一個一般命令的輸出, 比如cat或者echo, 傳遞到一個 "過濾命令"(在這個過濾命令中將處理輸入)中, 然後得到結果.cat $filename1 $filename2 | grep $search_word當然輸出的命令也可以傳遞到指令碼中.#!/bin/bash# uppercase.sh : 修改輸入, 全部轉換為大寫.tr 'a-z' 'A-Z'# 字元範圍必須被""引用起來來阻止產生單字元的檔案名稱.exit 0現在讓我們輸送ls -l的輸出到一個指令碼中.bash$ ls -l | ./uppercase.sh-RW-RW-R-- 1 BOZO BOZO 109 APR 7 19:49 1.TXT-RW-RW-R-- 1 BOZO BOZO 109 APR 14 16:48 2.TXT-RW-R--R-- 1 BOZO BOZO 725 APR 20 20:56 DATA-FILE 管道中的每個進程的stdout比須被下一個進程作為stdin來讀入. 否則, 資料流會阻塞, 並且管道將產生一些非預期的行為.cat file1 file2 | ls -l | sort# 從"cat file1 file2"中的輸出並沒出現. 作為子進程的啟動並執行管道, 不能夠改變指令碼的變數.variable="initial_value"echo "new_value" | read variableecho "variable = $variable" # variable = initial_value如果管道中的某個命令產生了一個異常,並中途失敗,那麼這個管道將過早的終止. 這種行為被叫做broken pipe, 並且這種狀態下將發送一個SIGPIPE 訊號. >| 強制重新導向(即使設定了noclobber 選項--就是-C 選項).這將強制的覆蓋一個現存檔案. || 邏輯或操作 ;用在兩個命令之間的時候,表示在前一個命令結束時,若傳回值為 false,繼續執行下一個命令 && 邏輯與;用在兩個命令之間的時候,表示在前一個命令結束時,若傳回值為 true,繼續執行下一個命令 & 後台運行看一個例子#!/bin/bash# background-loop.shfor i in 1 2 3 4 5 6 7 8 9 10 # 第一個迴圈.do echoecho -n "$i "done & # 在後台運行這個迴圈. # 在第2個迴圈之後, 將在某些時候執行. echo # 這個'echo'某些時候將不會顯示. for i in 11 12 13 14 15 16 17 18 19 20 # 第二個迴圈.doecho -n "$i "done echo # 這個'echo'某些時候將不會顯示. exit 0看一下結果:root@ubuntu:~/resource/study/shell_study# ./for_test 11 12 13 14 15 16 17 18 19 20 root@ubuntu:~/resource/study/shell_study# - 在所有的命令內如果想使用選項參數的話,前邊都要加上"-".1.參數選項2. 減號3. 重新導向stdin和stdout:cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)4.先前的工作目錄 cd -5.註:使用-開頭的檔案名稱和變數名可能會出現一些問題 + 一個命令或者過濾器的選項標記.~ home目錄~+ 當前工作目錄~- 先前工作目錄^ Regex中表示行首$IFS 用來做一些輸入命令的分隔字元, 預設情況下是空白其中命令的很多細節並沒有研究的很徹底,以後見到用到具體的命令再具體分析吧