1. 程式人生 > 實用技巧 >Shell指令碼eval、``和$()、[[和[、 $(( ))和(())、${}

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,(())命令,否則容易出錯。


[ 和 [[ 不同比較:

wKiom1dgybyC7296AABFF_FoaIY286.png

wKioL1dgy9qR7r-kAABCgj3jDnY210.png

由上面兩張圖可看出,[在進行字元比較的時候需要使用轉義字元\,而[[不需要


3.邏輯與和邏輯或

(1)"[":邏輯與:"-a";邏輯或:"-o";

(2)"[[":邏輯與:"&&";邏輯或:"||"

wKioL1dhFlzBJM25AAAuePJaczw923.png

4.

1)[ ... ]為shell命令,所以在其中的表示式應是它的命令列引數,所以串比較操作符">" 與"<"必須轉義,否則就變成IO重定向了;

(2)由於"[["是關鍵字,不會做命令列擴充套件,所以在[[中"<"與">"不需轉義,但是相對的語法就稍嚴格些。例如在[ ... ]中可以用引號括起操作符,因為在做命令列擴充套件時會去掉這些引號,而在` `.``.``.` `則不允許這樣做;

wKiom1dhFx7QLhRvAABQkCfcDsI538.png


5.` `.``.``.` `進行算術擴充套件,而[ ... ]不做

wKioL1dhGXWyl8XRAAA_2Y0H3q4458.png



$(( ))

用來作整數運算。在 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}

執行結果:

wKioL1dgE3HjmGgUAAA_5PJ47e0865.png



以上內容部分轉載

《完》

轉載於:https://blog.51cto.com/lingdandan/1789612