Shell 腳本編程(基礎(chǔ)篇)

基礎(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

參考資料

Linux Command Line and Shell Scripting Bible 3rd Edition

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市贬派,隨后出現(xiàn)的幾起案子急但,更是在濱河造成了極大的恐慌,老刑警劉巖搞乏,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件波桩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡请敦,警方通過查閱死者的電腦和手機(jī)镐躲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侍筛,“玉大人萤皂,你說我怎么就攤上這事∠灰” “怎么了裆熙?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)禽笑。 經(jīng)常有香客問我入录,道長(zhǎng),這世上最難降的妖魔是什么佳镜? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任僚稿,我火速辦了婚禮,結(jié)果婚禮上邀杏,老公的妹妹穿的比我還像新娘贫奠。我一直安慰自己唬血,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布唤崭。 她就那樣靜靜地躺著拷恨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谢肾。 梳的紋絲不亂的頭發(fā)上腕侄,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音芦疏,去河邊找鬼冕杠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酸茴,可吹牛的內(nèi)容都是我干的分预。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼薪捍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼笼痹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酪穿,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤凳干,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后被济,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體救赐,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年只磷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了经磅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喳瓣,死狀恐怖馋贤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畏陕,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布仿滔,位于F島的核電站惠毁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏崎页。R本人自食惡果不足惜鞠绰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望飒焦。 院中可真熱鬧蜈膨,春花似錦屿笼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至灶壶,卻和暖如春肝断,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驰凛。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工胸懈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恰响。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓趣钱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胚宦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子羔挡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容