bash字串操作以及shell中$(( ))與$( )還有${ }的區別
阿新 • • 發佈:2018-12-10
介紹下Shell中的${}、##和%%使用範例,本文給出了不同情況下得到的結果。 假設定義了一個變數為: 程式碼如下: file=/dir1/dir2/dir3/my.file.txt 可以用${ }分別替換得到不同的值: ${file#*/}:刪掉第一個 / 及其左邊的字串:dir1/dir2/dir3/my.file.txt ${file##*/}:刪掉最後一個 / 及其左邊的字串:my.file.txt ${file#*.}:刪掉第一個 . 及其左邊的字串:file.txt ${file##*.}:刪掉最後一個 . 及其左邊的字串:txt ${file%/*}:刪掉最後一個 / 及其右邊的字串:/dir1/dir2/dir3 ${file%%/*}:刪掉第一個 / 及其右邊的字串:(空值) ${file%.*}:刪掉最後一個 . 及其右邊的字串:/dir1/dir2/dir3/my.file ${file%%.*}:刪掉第一個 . 及其右邊的字串:/dir1/dir2/dir3/my 記憶的方法為: # 是 去掉左邊(鍵盤上#在 $ 的左邊) %是去掉右邊(鍵盤上% 在$ 的右邊) 單一符號是最小匹配;兩個符號是最大匹配 ${file:0:5}:提取最左邊的 5 個位元組:/dir1 ${file:5:5}:提取第 5 個位元組右邊的連續5個位元組:/dir2 也可以對變數值裡的字串作替換: ${file/dir/path}:將第一個dir 替換為path:/path1/dir2/dir3/my.file.txt ${file//dir/path}:將全部dir 替換為 path:/path1/path2/path3/my.file.txt
$( )與` `(反引號) 在bash shell中,$( )與` `(反引號)都是用來做命令替換(command substitution)用的。 $ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d) 得到上一星期天的日期 用$( )的理由 1. ` `很容易與' '(單引號)搞混。有時在一些奇怪的字形顯示中,兩種符號是一模一樣的(直豎兩點)。 2. 在多層次的複合替換中,` `須要額外的跳脫(\`)處理,而$( )則比較直觀。例如: command1 `command2 `command3` ` 原本的意圖是在command2 `command3`中先將command3替換出來給command2處理,然後再將結果傳給command1 `command2 ...`來處理。 然而,真正的結果在命令列中卻是分成了`command2`與` `兩段。 正確的輸入應該如下: command1 `command2 \`command3\` ` 換成$( )則一目瞭然: command1 $(command2 $(command3)) $( )的不足 ` `基本上可在全部的unix shell中使用,若寫成shell script移植性比較高。而$( )並不是每一種shell都能使用。 ${ }用來作變數替換 一般情況下,$var與${var}作用相同。但是用${ }會比較精確的界定變數名稱的範圍,例如: $ A=B $ echo $AB 原本是打算先將$A的結果替換出來,然後再補一個B字母於其後,但在命令列上,真正的結果卻是隻會替換變數名稱為AB的值出來。 使用${ }就沒問題了: $ echo ${A}B BB ${ }的一些特異功能 定義一個變數: file=/dir1/dir2/dir3/my.file.txt可以用${ }分別替換獲得不同的值: ${file#*/} 拿掉第一個 / 及其左邊的字串:dir1/dir2/dir3/my.file.txt ${file##*/} 拿掉最後一個 / 及其左邊的字串:my.file.txt ${file#*.} 拿掉第一個 . 及其左邊的字串:file.txt ${file##*.} 拿掉最後一個 . 及其左邊的字串:txt ${file%/*} 拿掉最後一個 / 及其右邊的字串:/dir1/dir2/dir3 ${file%%/*} 拿掉第一個 / 及其右邊的字串:(空值) ${file%.*} 拿掉最後一個 . 及其右邊的字串:/dir1/dir2/dir3/my.file ${file%%.*} 拿掉第一個 . 及其右邊的字串:/dir1/dir2/dir3/my 記憶的方法: # 去掉左邊(鍵盤上 # 在 $ 的左邊) % 去掉右邊(在鍵盤上 % 在 $ 的右邊) 單一符號是最小匹配,兩個符號是最大匹配。 ${file:0:5} 提取最左邊的 5 個位元組:/dir1 ${file:5:5} 提取第 5 個位元組右邊的連續 5 個位元組:/dir2也可以對變數值裡的字串作替換: ${file/dir/path} 將第一個 dir 替換為 path:/path1/dir2/dir3/my.file.txt ${file//dir/path} 將全部 dir 替換為 path:/path1/path2/path3/my.file.txt利用${ }還可針對不同的變數狀態賦值(未設定、空值、非空值): ${file-my.file.txt} 若 $file 未設定,則使用 my.file.txt 作傳回值。(空值及非空值時不作處理) ${file:-my.file.txt} 若 $file 未設定或為空值,則使用 my.file.txt 作傳回值。(非空值時不作處理) ${file+my.file.txt} 若 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(未設定時不作處理) ${file:+my.file.txt} 若 $file 為非空值,則使用 my.file.txt 作傳回值。(未設定及空值時不作處理) ${file=my.file.txt} 若 $file 未設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt。 (空值及非空值時不作處理) ${file:=my.file.txt} 若 $file 未設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt。 (非空值時不作處理) ${file?my.file.txt} :若 $file 未設定,則將 my.file.txt 輸出至 STDERR。(空值及非空值時不作處理) ${file:?my.file.txt} :若 $file 未設定或為空值,則將 my.file.txt 輸出至 STDERR。(非空值時不作處理) 以上的理解在於,一定要分清楚 unset 與 null 及 non-null 這三種賦值狀態。 一般而言,與 null 有關,若不帶 : 的話,null 不受影響,若帶 : 則連 null 也受影響。${#var} 可計算出變數值的長度: ${#file} 可得到 27,/dir1/dir2/dir3/my.file.txt 剛好是 27 個位元組。 bash陣列(array)處理方法 一般而言,A="a b c def"只是將 $A 替換為一個單一的字串,但是改為 A=(a b c def),則是將 $A 定義為陣列。 bash的陣列替換方法可參考如下方法: ${A[@]} 或 ${A[*]} 得到 a b c def(全部陣列) ${A[0]} 得到 a (第一個元素),${A[1]} 第二個... ${#A[@]} 或 ${#A[*]} 得到 4 (陣列數量) ${#A[0]} 得到 1 (第一個元素 a 的長度),${#A[3]} 得到 3 (第四個元素 def 的長度) A[3]=xyz 將第四個元素重新定義為 xyz $(( ))的用途 用來作整數運算。在 bash 中,$(( ))的整數運算子號大致有這些: + - * / 加、減、乘、除 % 餘數運算 & | ^ ! AND、OR、XOR、NOT運算 舉例: $ a=5; b=7; c=2 $ echo $((a+b*c)) 19 $ echo $(((a+b)/c)) 6 $ echo $(((a*b)%c)) 1 在$(( ))中的變數名稱也可以在其前面加 $ 符號:$(($a+$b*$c))也可以得到 19 的結果。 此外,$(( ))還可以作不同進位制(如二進位制、八進位、十六進位制)運算,只是輸出結果皆為十進位制而已。 echo $((16#2a)) 結果為 42 (16進位轉十進位制) 舉一個實用的例子: 當前的 umask 是 022,新建檔案的許可權為: $ umask 022 $ echo "obase=8; $(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc 644 事實上,單純用(( ))也可以重定義變數值,或作testing: a=5; ((a++)) 將 $a 重定義為 6 a=5; ((a–)) a=4 a=5; b=7; ((a < b)) 會得到 0 (true) 的返回值 常見的用於(( ))的測試符號有以下這些: < 小於 > 大於 <= 小於或等於 >= 大於或等於 == 等於 != 不等於