Shell指令碼eval、``和$()、[[和[、 $(( ))和(())、${}
eval
eval的作用是再次執行命令列處理,也就是說,對一個命令列,執行兩次命令列處理。
語法:eval cmdLine
eval會對後面的 cmdLine 進行兩遍掃描,如果第一遍掃描後 cmdLine 是個普通命令,則執行此命令;
如果 cmdLine 中含有變數的間接引用,則保證間接引用的語義。
eval echo \$$# 取得最後一個引數
如:cat last
eval echo \$$#
./last one teo three four
four
第一遍掃描後,shell把反斜槓去掉了。當shell再次掃描該行時,它替換了$4的值,並執行echo命令
``(反引號)和$()
在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都能使用。
[[和[
1."[[",是關鍵字,許多shell(如ash bsh)並不支援這種方式。ksh, bash(據說從2.02起引入對[[的支援)等支援。
"["是一條命令, 與test等價,大多數shell都支援。在現代的大多數sh實現中,"["與"test"是內部(builtin)命令。
2.二者都支援算術比較和字串比較表示式(具體使用可能有點不同)
(1)"-gt", "-lt"是算術比較操作符,用於比較整數的大小。
(2)">", "<"是字串比較操作符,用於比較字串的大小,使用字典順序,與當前的locale有關。
(3)建議在使用數值比較的時候,使用let,(())命令,否則容易出錯。
[ 和 [[ 不同比較:
由上面兩張圖可看出,[在進行字元比較的時候需要使用轉義字元\,而[[不需要
3.邏輯與和邏輯或
(1)"[":邏輯與:"-a";邏輯或:"-o";
(2)"[[":邏輯與:"&&";邏輯或:"||"
4.
1)[ ... ]為shell命令,所以在其中的表示式應是它的命令列引數,所以串比較操作符">" 與"<"必須轉義,否則就變成IO重定向了;
(2)由於"[["是關鍵字,不會做命令列擴充套件,所以在[[中"<"與">"不需轉義,但是相對的語法就稍嚴格些。例如在[ ... ]中可以用引號括起操作符,因為在做命令列擴充套件時會去掉這些引號,而在` `.``.``.` `則不允許這樣做;
5.` `.``.``.` `進行算術擴充套件,而[ ... ]不做
$(( ))
用來作整數運算。在 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) 的返回值
常見的用於(( ))的測試符號有以下這些:
< 小於
> 大於
<= 小於或等於
>= 大於或等於
== 等於
!= 不等於
${ }
它其實就是用來作變數替換用的。
一般情況下,$var 與 ${var} 並沒有啥不一樣。但是用 ${ } 會比較精確的界定變數名稱的範圍。
再來看${}的一些特異功能
定義一個變數:
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:4}:提取最左邊的 4 個位元組:dir1
${file:4:5}:提取第 54個位元組右邊的連續 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} :變數值為26個位元組
test.sh:
file=dir1/dir2/dir3/my.file.txt echo${file#*/} echo${file##*/} echo${file#*.} echo${file##*.} echo${file%/*} echo${file%%/*} echo${file%.*} echo${file%%.*} echo${file:0:4} echo${file:4:5} echo${file/dir/path} echo${file//dir/path} echo${#file}
執行結果:
以上內容部分轉載
《完》
轉載於:https://blog.51cto.com/lingdandan/1789612