基礎(chǔ)篇
一陷猫、輸出信息
大部分 Shell 命令都會(huì)生成自己的輸出信息祠乃,在腳本運(yùn)行時(shí)打印到終端屏幕上缴渊。但是很多時(shí)候藐俺,仍需要在輸出的信息中添加上自己的內(nèi)容炊甲,以提示用戶腳本運(yùn)行時(shí)究竟發(fā)生著什么盯仪,達(dá)到更好的交互效果。
echo
命令可以用來打印字符串內(nèi)容蜜葱。
$ echo This is a test
This is a test
$
PS:默認(rèn)是不需要將 echo
命令后面的字符串包含在一對(duì)引號(hào)中的
echo
可以使用引號(hào)作為文本字符串的分隔符全景。如:
$ echo 'Hello
> World'
Hello
World
當(dāng)輸出的文本內(nèi)容中本來就有引號(hào)出現(xiàn)時(shí),如(Let's see if this'll work
)牵囤,可以結(jié)合單爸黄、雙引號(hào)的使用,或者使用轉(zhuǎn)義符(\
)前綴
# 引號(hào)作為字符串分隔符而不是文本內(nèi)容
$ echo Let's see if this'll work
Lets see if thisll work
# 使用 \ 前綴進(jìn)行轉(zhuǎn)義
$ echo Let\'s see if this\'ll work
Let's see if this'll work
# 使用雙引號(hào)作為分隔符揭鳞,單引號(hào)作為中間的文本正常輸出
$ echo "Let's see if this'll work"
Let's see if this'll work
腳本的執(zhí)行權(quán)限
默認(rèn)創(chuàng)建的腳本文件沒有執(zhí)行權(quán)限炕贵,不能直接在命令行中運(yùn)行。
如創(chuàng)建包含以下內(nèi)容的腳本文件 info.sh
:
#!/bin/bash
echo The time and date are:
date
echo "Let's see who's logged into the system:"
who
直接執(zhí)行上述腳本時(shí)會(huì)提示 permission denied
錯(cuò)誤:
$ ./info.sh
zsh: permission denied: ./info.sh
需要使用 chomd +x filename
命令為該腳本文件添加執(zhí)行權(quán)限后再運(yùn)行野崇,效果如下:
$ chmod +x info.sh
$ ./info.sh
The time and date are:
Wed Oct 31 11:48:07 CST 2018
Let's see who's logged into the system:
starky console Oct 28 12:42
starky ttys000 Oct 29 16:52
starky ttys001 Oct 31 11:23
二称开、變量
1. 系統(tǒng)環(huán)境變量
在 Shell 腳本中可以直接訪問系統(tǒng)中的環(huán)境變量,以獲取相關(guān)的系統(tǒng)信息(如計(jì)算機(jī)名稱乓梨,當(dāng)前登錄用戶的賬戶名鳖轰、 UID 和主目錄等)。
當(dāng)前定義的所有環(huán)境變量可以通過 set
命令獲取扶镀。
$ set
...
HISTCMD=2217
HISTFILE=/Users/starky/.zsh_history
HISTSIZE=50000
HOME=/Users/starky
HOST=skitars-MacBook-Pro.local
IFS=$' \t\n\C-@'
ITERM_PROFILE=starky
...
當(dāng)需要在 Shell 腳本中使用具體某個(gè)環(huán)境變量的值時(shí)蕴侣,可以用環(huán)境變量名稱加上 $
前綴表示(如 $HOST
)。
編輯如下 sys_info.sh
文件:
#!/bin/bash
echo User info for userid: $USER
echo UID: $UID
echo HOME: $HOME
運(yùn)行效果如下:
$ chmod +x sys_info.sh
$ ./sys_info.sh
User info for userid: starky
UID: 501
HOME: /Users/starky
PS:由于在 Shell 腳本中臭觉,$
作為變量的前綴符昆雀,所以當(dāng)需要在文本輸出中顯示 $
時(shí),應(yīng)使用轉(zhuǎn)義蝠筑。
# $15 被當(dāng)成了代入到字符串中的“變量”
$ echo "The cost of the item is $15"
The cost of the item is
# 使用 \ 轉(zhuǎn)義后正常打印 $ 字符
$ echo "The cost of the item is \$15"
The cost of the item is $15
2. 用戶自定義變量
Shell 腳本允許用戶自行定義和使用變量狞膘,這樣就可以將腳本中用到的數(shù)據(jù)臨時(shí)存儲(chǔ)在指定的變量中,使用時(shí)再通過 $變量名
的形式獲取什乙。
- 變量賦值:
var=value
(注意=
號(hào)兩邊不能有空格挽封,即var = value
是錯(cuò)誤的) - 變量使用:
$var
PS:Shell 腳本中的變量名區(qū)分大小寫
Shell 腳本會(huì)自動(dòng)判斷變量值的數(shù)據(jù)類型
變量的有效性貫穿腳本的整個(gè)生命周期,即腳本執(zhí)行完畢后變量會(huì)自行刪除
編輯如下 variables.sh
文件:
#!/bin/bash
days=10
guest="Katie"
echo "$guest checked in $days days ago"
days=5
guest="Jessica"
echo "$guest checked in $days days ago"
運(yùn)行效果如下:
$ chmod +x variables.sh
$ ./variables.sh
Katie checked in 10 days ago
Jessica checked in 5 days ago
$ echo $days
可以看到稳强,腳本退出后场仲,腳本中定義的 $days
變量又恢復(fù)為未定義的狀態(tài)。
三退疫、命令替換
Shell 腳本最有用處的特性之一渠缕,就是它可以提取某個(gè)命令的輸出信息,并將其賦值給一個(gè)變量褒繁。
可以通過以下兩種方式將命令輸出賦值給變量:
- 反單引號(hào)(`)
-
$()
格式
如:
# 使用 date 命令獲取當(dāng)前的日期和時(shí)間
$ date
Thu Nov 1 01:03:02 CST 2018
# 將 date 命令的輸出(即當(dāng)前日期和時(shí)間)賦值給 var1 變量
$ var1=`date`
$ echo Today is: $var1
Today is: Thu Nov 1 01:03:15 CST 2018
# 將 date 命令的輸出賦值給 var2 變量(使用 $() 格式)
$ var2=$(date)
$ echo Today is: $var2
Today is: Thu Nov 1 01:03:36 CST 2018
示例程序:
使用命令替換完成一個(gè)腳本(log.sh
)亦鳞,該腳本可以創(chuàng)建以當(dāng)前時(shí)間水印為后綴的文本文件,內(nèi)容為 /usr/bin
目錄下的所有文件列表。
#!/bin/bash
today=$(date +%y%m%d%H%M%S)
ls -al /usr/bin > log.$today
echo The file log.$today has been created, you can check it later.
其中 date +%y%m%d%H%M%S
命令可以輸出純數(shù)字格式的日期和時(shí)間
運(yùn)行效果如下:
$ chmod +x log.sh
$ ./log.sh
The file log.181101012159 has been created, you can check it later.
$ ls log*
log.181101012159 log.sh
$ head log.181101012159
total 103992
drwxr-xr-x 971 root wheel 31072 Oct 13 17:44 .
drwxr-xr-x@ 9 root wheel 288 Sep 21 12:01 ..
-rwxr-xr-x 4 root wheel 925 Aug 18 08:45 2to3-
lrwxr-xr-x 1 root wheel 74 Oct 13 17:44 2to3-2.7 -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/2to3-2.7
-rwxr-xr-x 1 root wheel 55072 Sep 21 12:16 AssetCacheLocatorUtil
-rwxr-xr-x 1 root wheel 53472 Sep 21 12:16 AssetCacheManagerUtil
-rwxr-xr-x 1 root wheel 48256 Sep 21 12:17 AssetCacheTetheratorUtil
-rwxr-xr-x 1 root wheel 18320 Sep 21 12:17 BuildStrings
-rwxr-xr-x 1 root wheel 18288 Sep 21 12:17 CpMac
四燕差、重定向輸入和輸出
1. 輸出重定向
最基本的重定向遭笋,就是通過大于號(hào)(>),將某個(gè)命令的輸出內(nèi)容保存至一個(gè)文件中徒探。
格式:command > outputfile
$ date > current_date.txt
$ ls -l current_date.txt
-rw-r--r-- 1 starky staff 29 Nov 1 01:29 current_date.txt
$ cat current_date.txt
Thu Nov 1 01:29:45 CST 2018
PS:如使用重定向時(shí)瓦呼,指定的文件已存在,則該文件的原始內(nèi)容會(huì)被新內(nèi)容覆蓋测暗。
如果只是想在文件末尾追加內(nèi)容央串,則可以使用雙大于號(hào)(>>)
$ date >> current_date.txt
$ cat current_date.txt
Thu Nov 1 01:29:45 CST 2018
Thu Nov 1 01:34:03 CST 2018
2. 輸入重定向
輸入重定向和輸出重定向相反。即從文件中讀取內(nèi)容碗啄,并將該內(nèi)容傳遞給某個(gè)命令质和。
格式:command < inputfile
$ ls -l /Users/starky
total 49864
drwx------@ 3 starky staff 96 Oct 13 18:00 Applications
drwx------+ 23 starky staff 736 Oct 31 19:14 Desktop
drwx------+ 21 starky staff 672 Oct 31 19:15 Documents
drwx------+ 37 starky staff 1184 Oct 30 20:18 Downloads
drwx------+ 72 starky staff 2304 Oct 27 01:38 Library
drwx------+ 6 starky staff 192 Oct 29 10:34 Movies
drwx------+ 3 starky staff 96 Sep 27 13:13 Music
...
$ cat directory.txt
/Users/starky
$ ls -l < directory.txt
total 49864
drwx------@ 3 starky staff 96 Oct 13 18:00 Applications
drwx------+ 23 starky staff 736 Oct 31 19:14 Desktop
drwx------+ 21 starky staff 672 Oct 31 19:15 Documents
drwx------+ 37 starky staff 1184 Oct 30 20:18 Downloads
drwx------+ 72 starky staff 2304 Oct 27 01:38 Library
drwx------+ 6 starky staff 192 Oct 29 10:34 Movies
drwx------+ 3 starky staff 96 Sep 27 13:13 Music
...
3. 管道
有些時(shí)候,需要將某個(gè)命令的輸出內(nèi)容作為另一個(gè)命令的輸入稚字。如:
$ ls -al > tmp_file
$ grep vim < tmp_file
drwxr-xr-x 3 starky staff 96 Oct 20 15:45 .vim
-rw------- 1 starky staff 23799 Nov 1 01:40 .viminfo
-rw-r--r-- 1 starky staff 3935 Oct 21 01:31 .vimrc
-rw-r--r-- 1 starky staff 24849808 Oct 25 21:02 vim.tar.gz
上面的命令先將當(dāng)前目錄下的文件列表(ls -al
)保存在 tmp_file
中饲宿,再使用 grep
命令讀取 tmp_file 的內(nèi)容,篩選文件名中包含 vim 的文件胆描。
其實(shí)可以通過管道(|
)的使用瘫想,將前面命令的輸出,定向給后面的命令作為輸入袄友。
格式:command1 | command2
ls -al | grep vim
drwxr-xr-x 3 starky staff 96 Oct 20 15:45 .vim
-rw------- 1 starky staff 23799 Nov 1 01:40 .viminfo
-rw-r--r-- 1 starky staff 3935 Oct 21 01:31 .vimrc
-rw-r--r-- 1 starky staff 24849808 Oct 25 21:02 vim.tar.gz
五殿托、數(shù)學(xué)運(yùn)算
操作數(shù)學(xué)運(yùn)算對(duì)于任何編程語言來說霹菊,都是一個(gè)很重要的特性剧蚣。但是 Shell 腳本并不能直接完成算術(shù)運(yùn)算的操作,只能通過以下兩種方式來實(shí)現(xiàn)旋廷。
1. expr 命令
Shell 提供了一個(gè)特殊的命令(expr
)用來處理數(shù)學(xué)算式鸠按,如:
$ expr 1 + 2
3
PS:注意算式中 +
號(hào)兩邊的空格
expr 命令支持的算術(shù)操作符如下:
操作符 | 含義 |
---|---|
ARG1 || ARG2 | 如果兩個(gè)參數(shù)值都不為 null 或 0,返回 ARG1饶碘,否則返回 ARG2 |
ARG1 && ARG2 | 如果兩個(gè)參數(shù)值都不為 null 或 0目尖,返回 ARG1,否則返回 0 |
ARG1 < ARG2 | 如果 ARG1 小于 ARG2扎运,返回 1瑟曲,否則返回 0 |
ARG1 > ARG2 | 如果 ARG1 大于 ARG2,返回 1豪治,否則返回 0 |
ARG1 = ARG2 | 如果 ARG1 等于 ARG2洞拨,返回 1,否則返回 0 |
ARG1 >= ARG2 | 如果 ARG1 大于或等于 ARG2负拟,返回 1烦衣,否則返回 0 |
ARG1 <= ARG2 | 如果 ARG1 小于或等于 ARG2,返回 1,否則返回 0 |
ARG1 != ARG2 | 如果 ARG1 不等于 ARG2花吟,返回 1秸歧,否則返回 0 |
ARG1 + ARG2 | 返回 ARG1 與 ARG2 的數(shù)字加和 |
ARG1 - ARG2 | 求 ARG1 減去 ARG2 的數(shù)字差 |
ARG1 * ARG2 | 返回 ARG1 與 ARG2 的數(shù)字乘積 |
ARG1 / ARG2 | 求 ARG1 除以 ARG2 的數(shù)字商(結(jié)果為整數(shù)) |
ARG1 % ARG2 | 對(duì) ARG1 和 ARG2 進(jìn)行求余操作 |
數(shù)學(xué)運(yùn)算示例(divide.sh
):
#!/bin/bash
var1=10
var2=20
var3=`expr $var2 / $var1`
echo $var2 divided by $var1 equals $var3
運(yùn)行效果:
$ chmod +x divide.sh
$ ./divide.sh
20 divided by 10 equals 2
2. 使用中括號(hào)
Bash Shell 中的 expr
命令主要是為了保持和 Bourne Shell 的兼容性勾拉,它其實(shí)還提供了一種更簡(jiǎn)單的方式用來處理數(shù)學(xué)運(yùn)算突琳。即使用這樣的形式:
$[ operation ]
如下面的腳本(compute.sh
)
#!/bin/bash
var1=100
var2=50
var3=45
result=$[$var1 * ($var2 - $var3)]
echo The final result is $result
運(yùn)行效果:
$ chmod +x compute.sh
$ ./compute.sh
The final result is 500
但是在進(jìn)行除法運(yùn)算時(shí),上面的方式只支持整數(shù)努溃。如兩個(gè)數(shù)相除結(jié)果為小數(shù)今布,則該結(jié)果會(huì)舍去小數(shù)部分只保留整數(shù)纱耻。
$ var1=10
$ var2=3
$ result=$[$var1 / $var2]
$ echo The result is $result
The result is 3
3. 浮點(diǎn)數(shù)運(yùn)算
有很多種方案可以克服 bash 的整數(shù)限制,最常用的一種就是使用系統(tǒng)內(nèi)置的 bash calculator险耀,即 bc
程序弄喘。
bash calculator 其實(shí)是一種支持浮點(diǎn)數(shù)運(yùn)算的編程語言,可以識(shí)別以下幾種類型的數(shù)據(jù):
- 數(shù)字(整數(shù)和浮點(diǎn)數(shù))
- 變量(簡(jiǎn)單變量和數(shù)組)
- 注釋(單行注釋
#
和多行注釋/* */
) - 表達(dá)式
- 編程語句(如
if-then
語句) - 函數(shù)
$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
12 * 5.4
64.8
3.156 * (3 + 5)
25.248
quit
計(jì)算結(jié)果精確到的小數(shù)位數(shù)是通過一個(gè)內(nèi)建的 scale
變量定義的甩牺,默認(rèn)的 scale 數(shù)值為 0(即默認(rèn)舍去商的小數(shù)位數(shù)):
$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
bc
程序也支持自定義變量:
$ bc -q
var1=10
var1 * 4
40
var2=var1 / 5
print var2
2
quit
4. 在腳本中使用 bc
可以通過管道將數(shù)學(xué)表達(dá)式傳遞給 bc
程序蘑志,再將計(jì)算得出的結(jié)果通過賦值語句賦值給某個(gè)變量:
variable=$(echo "options; expression" | bc)
其中 variable=$(...)
用于提取命令的輸出并賦值給一個(gè)變量(參考第三章命令替換)
如下面的腳本(bc1.sh
):
#!/bin/bash
var1=100
var2=45
var3=$(echo "scale=4; $var1 / $var2" | bc)
echo The answer for this is $var3
運(yùn)行效果:
$ chmod +x bc1.sh
$ ./bc1.sh
The answer for this is 2.2222
更復(fù)雜的形式
在腳本中使用 bc
還可以通過如下的形式:
variable=$(bc << EOF
options
statements
expressions
EOF
)
示例程序如下(bc2.sh
):
#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(bc << EOF
scale = 4
a1=$var1 * $var2
b1=$var3 * $var4
a1 + b1
EOF
)
echo The final answer for this mess is $var5
運(yùn)行結(jié)果:
$ chmod +x bc2.sh
$ ./bc2.sh
The final answer for this mess is 2813.9882