內(nèi)容
- 使用多個命令
- 創(chuàng)建腳本文件
- 顯示消息
- 使用變量
- 輸入輸出重定向
- 管道
- 數(shù)學運算
- 退出腳本
使用多個命令
如果多個命令一起使用,可以放在一行并用分號分隔祝峻。
wsx@wsx-ubuntu:~$ date; who
2017年 07月 26日 星期三 09:53:43 CST
wsx tty7 2017-07-26 09:48 (:0)
創(chuàng)建腳本文件
在創(chuàng)建腳本文件時,必須在文件的第一行指定要使用的shell猴蹂,格式為:
#!/bin/bash
腳本文件的第一行中#
后的驚嘆號會告訴shell使用哪個shell來運行腳本(如果是其他編碼語言腳本退子,像python,第一行類似)宫仗。
其他地方的#
用作注釋行。
添加名為test1
的腳本文件旁仿,內(nèi)容為:
#!/bin/bash
# This script displays the date and who's logged on
date
who
現(xiàn)在運行腳本藕夫,結(jié)果會是:
wsx@wsx-ubuntu:~/script_learn$ test1
未找到 'test1' 命令,您要輸入的是否是:
命令 'testr' 來自于包 'python3-testrepository' (main)
命令 'testr' 來自于包 'python-testrepository' (universe)
命令 'test' 來自于包 'coreutils' (main)
test1:未找到命令
我們現(xiàn)在需要做的是讓bash shell能夠找到我們的腳本文件枯冈。shell會通過PATH
環(huán)境變量來查找命令毅贮,我們可以看看:
wsx@wsx-ubuntu:~/script_learn$ echo $PATH
/home/wsx/Anaconda/bin:/home/wsx/Anoconda/ENTER/bin:/usr/lib/jvm/default-java/bin:/home/wsx/bin:/home/wsx/Anaconda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
很顯然,我們的文件沒有在這些目錄范圍內(nèi)尘奏。要讓shell找到test1腳本滩褥,我們可以采取以下兩種做法之一:
- 將shell腳本文件所處的目錄添加到
PATH
環(huán)境變量中; - 在提示符中用絕對路徑或相對路徑來引用shell腳本文件炫加。
第二種方法比較簡單瑰煎,我們在這里試試:
wsx@wsx-ubuntu:~/script_learn$ ./test1
bash: ./test1: 權(quán)限不夠
wsx@wsx-ubuntu:~/script_learn$ ll test1 # 發(fā)現(xiàn)權(quán)限不夠铺然,查看文件的權(quán)限
-rw-rw-r-- 1 wsx wsx 73 7月 26 10:03 test1
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test1 # 修改權(quán)限,添加可執(zhí)行屬性
wsx@wsx-ubuntu:~/script_learn$ ./test1 # 成功運行腳本
2017年 07月 26日 星期三 10:09:23 CST
wsx tty7 2017-07-26 09:48 (:0)
顯示消息
在echo
命令后面加上一個字符串酒甸,就能顯示出這個文本字符串魄健。這種方式可以添加自己的文本消息來告訴腳本用戶腳本正在做什么。
wsx@wsx-ubuntu:~/script_learn$ echo This is a test
This is a test
如果文本本身帶有字符串插勤,我們需要用單引號或雙引號來劃定文本字符串沽瘦。
wsx@wsx-ubuntu:~/script_learn$ echo "Let's see if this'll work"
Let's see if this'll work
我們修改下之前的test1文件岁忘,增加消息顯示:
#!/bin/bash
# This script displays the date and who's logged on
echo The time and date are:
date
echo "Let's see who's logged into the system"
who
運行:
wsx@wsx-ubuntu:~/script_learn$ ./test1
The time and date are:
2017年 07月 26日 星期三 10:17:59 CST
Let's see who's logged into the system
wsx tty7 2017-07-26 09:48 (:0)
如果想把文本字符串和命令輸出顯示在同一行中笼恰,可以用echo
語句的-n
參數(shù)。需要在字符串的兩側(cè)加上引號,并且保證字符串尾部有一個空格(不然字符串和命令輸出就粘連到一起了)卤橄。
#!/bin/bash
# This script displays the date and who's logged on
echo -n "The time and date are: "
date
echo "Let's see who's logged into the system: "
who
# 運行結(jié)果輸出
wsx@wsx-ubuntu:~/script_learn$ ./test1
The time and date are: 2017年 07月 26日 星期三 10:24:04 CST
Let's see who's logged into the system:
wsx tty7 2017-07-26 09:48 (:0)
使用變量
變量允許我們臨時性地將信息存儲在shell腳本中,以便和腳本中的其他命令一起使用臂外。
環(huán)境變量
shell維護著一組環(huán)境變量窟扑,用來記錄特定的系統(tǒng)信息。比如系統(tǒng)的名稱漏健、登錄到系統(tǒng)上的用戶名嚎货、用戶的系統(tǒng)ID(也稱為UID)、用戶默認主目錄以及shell查找程序的搜索路徑蔫浆。
使用set
命令顯示一份完整的當前環(huán)境變量列表殖属。env
與printenv
命令都可以顯示全局變量。(這些命令輸出結(jié)果比較多瓦盛,不展示了洗显。之前關(guān)于環(huán)境變量的筆記有比較詳細的描述。)
在環(huán)境變量名稱之前加上美元符可以使用這些環(huán)境變量原环。
wsx@wsx-ubuntu:~/script_learn$ cat test2
#! /bin/bash
# display user information from the system
echo "User info for userid: $USER"
echo UID: $UID
echo HOME: $HOME
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test2
wsx@wsx-ubuntu:~/script_learn$ ./test2
User info for userid: wsx
UID: 1000
HOME: /home/wsx
可以想象的到挠唆,如果我們想要使用實際的美元符而不是引用變量,肯定會出問題嘱吗。這時候我們需要在美元符前面加上\
進行轉(zhuǎn)義玄组,以顯示美元符本身。
用戶變量
使用等號將值賦給用戶變量谒麦。注意俄讹,在變量、等號和值之間不能出現(xiàn)空格绕德!這個是初學者常見的一個問題颅悉,本人也非常不太適應(yīng)這個。因為在其他語言中不區(qū)分等號兩邊的空格迁匠,相信接觸過其他腳本的朋友們肯定有習慣打空格使代碼美觀的剩瓶,這在bash shell中是萬萬行不通滴驹溃。
一個使用的例子:
wsx@wsx-ubuntu:~/script_learn$ cat test3
#!/bin/bash
# testing variables
days=10
guest="Katie"
echo "$guest checked in $days days ago"
days=5
guest="Jessica"
echo "$guest checked in $days days ago"
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test3
wsx@wsx-ubuntu:~/script_learn$ ./test3
Katie checked in 10 days ago
Jessica checked in 5 days ago
變量每次被引用時,都會輸出當前賦給它的值延曙。重要的是要記住豌鹤,引用一個變量值時需要使用美元符,而引用變量來對其進行賦值時則不需要使用美元符枝缔。
命令替換
shell腳本最有用的特性之一就是可以從命令輸出中提取信息布疙,并將其賦給變量。
有兩種方法可以將命令輸出賦給變量:
- 反引號字符(`)
- $()格式
要么用一對反引號把整個命令行命令圍起來:
testing=`date`
要么使用$()格式
testing=$(date)
下面是一個例子愿卸,在腳本中通過命令替換獲得當前日期并用它來生成唯一文件名:
wsx@wsx-ubuntu:~/script_learn$ cat test4
#!/bin/bash
# copy the /usr/bin directory listing to a log file
today=$(date +%y%m%d)
ls /usr/bin -al > log.$today
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test4
wsx@wsx-ubuntu:~/script_learn$ ./test4
重定向輸入和輸出
通過幾個操作符進行重定向灵临,我們可以將命令的結(jié)果輸出到另外的位置(文件)。當然趴荸,重定向可以用于輸入儒溉。
輸出重定向
最基本的操作符是>
。比如我們想要輸出命令結(jié)果到一個指定文件:
wsx@wsx-ubuntu:~/script_learn$ date > test6
wsx@wsx-ubuntu:~/script_learn$ ls -l test6
-rw-rw-r-- 1 wsx wsx 43 7月 26 16:42 test6
wsx@wsx-ubuntu:~/script_learn$ cat test6
2017年 07月 26日 星期三 16:42:34 CST
如果想要將命令的輸出追加到已有文件中发钝,需要用雙大于號(>>)來追加數(shù)據(jù)顿涣。
輸入重定向
輸入重定向和輸出重定向正好相反。輸入重定向?qū)⑽募膬?nèi)容重定向到命令酝豪,而非將命令的輸出重定向到文件涛碑。
使用的符號是小于號(<)。
一種簡單的記憶方法是:在命令行上孵淘,命令總是在左側(cè)蒲障,而重定向符號“指向”數(shù)據(jù)流動的方向。小于號說明數(shù)據(jù)正在從輸入文件流向命令瘫证。
比如用wc命令檢查文本的行數(shù)揉阎、詞數(shù)和字節(jié)數(shù)。
wsx@wsx-ubuntu:~/script_learn$ wc < test6
1 6 43
另一種輸入重定向的方法是內(nèi)聯(lián)輸入重定向痛悯。它無需使用文件進行重定向余黎,只需要在命令行中指定用于輸入重定向的數(shù)據(jù)即可。它使用的符號是遠小于號(<<)载萌,除了這個符號惧财,我們還需要指定一個文本標記用來劃分輸入數(shù)據(jù)的開始和結(jié)尾。任何字符串都可以作為文本標記扭仁,但在數(shù)據(jù)的開始和結(jié)尾文本標記必須一致垮衷。
wsx@wsx-ubuntu:~/script_learn$ wc << EOF
> test string1
> test string2
> test string3
> EOF
3 6 39
它的形式為:
command << marker
data
marker
管道
有時候需要將一個命令的輸出作為另一個命令的輸入。通過|
符號分隔命令即可實現(xiàn)管道乖坠。
比如我想查看某個文件(test1)的前兩行并進行排序搀突,操作如下:
wsx@wsx-ubuntu:~/script_learn$ cat test1
#!/bin/bash
# This script displays the date and who's logged on
echo -n "The time and date are: "
date
echo "Let's see who's logged into the system: "
who
wsx@wsx-ubuntu:~/script_learn$ cat test1 | head -2 | sort
#!/bin/bash
# This script displays the date and who's logged on
管道的強大之處在于可以根據(jù)自己的需求靈活地組合和使用各種linux命令工具。這里只是一個簡單的例子熊泵,要熟練掌握少不了平時多多研究和練習仰迁。
執(zhí)行數(shù)學運算
對shell腳本來說甸昏,執(zhí)行數(shù)學運算非常麻煩。有兩種實現(xiàn)方式徐许。
expr命令
expr
命令允許在命令行上處理數(shù)學表達式施蜜,但是特別笨拙。(Bourne shell中)
wsx@wsx-ubuntu:~/script_learn$ exrpr 1 + 5
未找到 'exrpr' 命令雌隅,您要輸入的是否是:
命令 'expr' 來自于包 'coreutils' (main)
exrpr:未找到命令
看到?jīng)]有翻默,那算了。它基本涉及的操作跟我們使用的其他語言是一致的恰起。但是有些問題需要處理修械,像*
是通配符,在運算是是做乘號處理的检盼,需要進行轉(zhuǎn)義肯污。
使用方括號
bash shell提供了一種更簡單的方法來執(zhí)行數(shù)學表達式。在bash中梯皿,在將一個數(shù)學運算結(jié)果賦給某個變量時仇箱,可以用美元符和方括號($[operator])將數(shù)學表達式圍起來县恕。
wsx@wsx-ubuntu:~/script_learn$ var1=$[1+5]
wsx@wsx-ubuntu:~/script_learn$ echo $var1
6
wsx@wsx-ubuntu:~/script_learn$ var2=$[$var1+2]
wsx@wsx-ubuntu:~/script_learn$ echo $var2
8
這種方式不僅方便东羹,而且因為在方括號內(nèi),不會讓shell誤解乘號或其他符號忠烛。
但bash shell計算有一個主要限制:它只支持整數(shù)運算属提!
浮點解決方案
最常見的方案是用內(nèi)建的bash計算器。它實際上是一門編程語言美尸,它允許在命令行中輸入浮點表達式冤议,然后解釋并計算該表達式,最后返回結(jié)果师坎。bash計算器能夠識別:
- 數(shù)字(整數(shù)和浮點數(shù))
- 變量(簡單變量和數(shù)組)
- 注釋(/* */開始的行)
- 表達式
- 編程語句
- 函數(shù)
wsx@wsx-ubuntu:~/script_learn$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 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
在腳本中使用bc
可以用命令替換運行bc命令恕酸,并將輸出賦給一個變量】杪基本格式如下:
variable=$(echo "options; expression" | bc)
options設(shè)置變量蕊温,expression參數(shù)定義了通過bc執(zhí)行的數(shù)學表達式。
看一個簡單實例:
wsx@wsx-ubuntu:~/script_learn$ cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44/5" | bc)
echo The answer is $var1
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test9
wsx@wsx-ubuntu:~/script_learn$ ./test9
The answer is .6880
這個例子將scale
變量設(shè)置為四位小數(shù)遏乔,并在expression
部分指定了特定的運算义矛。
這個方法適用于較短的運算,但有時我們會涉及更多的數(shù)字盟萨。如果需要進行大量運算凉翻,在一個命令行中列出多個表達式就會有點麻煩。
這里有一個解決方法:使用內(nèi)聯(lián)輸入重定向捻激,將一個文件重定向到bc命令來處理制轰。格式為:
variable=$(bc << EOF
options
statements
expressions
EOF)
EOF
文本字符串標識了內(nèi)聯(lián)重定向數(shù)據(jù)的起始前计。注意,仍然需要命令替換符號將bc命令的輸出賦給變量垃杖。
下面是一個例子:
wsx@wsx-ubuntu:~/script_learn$ cat test10
#!/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
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test10
wsx@wsx-ubuntu:~/script_learn$ ./test10
The final answer for this mess is 2813.9882
在普通的shell腳本中残炮,數(shù)字默認當做字符串處理。這也是為什么我們腳本處理計算麻煩和我們需要特定的工具和方法來進行處理缩滨。一定要注意區(qū)分势就。
退出腳本
前面運行的腳本都是命令執(zhí)行完成,腳本自動結(jié)束脉漏。其實我們可以用更為優(yōu)雅的方式告訴shell命令運行完成苞冯,因為每個命令都使用退出狀態(tài)碼(exit status),它是一個0-255的整數(shù)值侧巨,我們可以捕獲這個值并在腳本中使用舅锄。
Linux提供了一個專門的變量$?
來保存上個已執(zhí)行命令的退出狀態(tài)碼。
wsx@wsx-ubuntu:~/script_learn$ date
2017年 07月 27日 星期四 10:44:18 CST
wsx@wsx-ubuntu:~/script_learn$ echo $?
0
按照慣例司忱,一個成功結(jié)束的命令的退出狀態(tài)碼是0皇忿。如果有錯誤,則顯示一個正數(shù)值坦仍。
Linux錯誤退出狀態(tài)碼沒有什么標準鳍烁,但有一些參考:
狀態(tài)碼 | 描述 |
---|---|
0 | 命令成功結(jié)束 |
1 | 一般性未知錯誤 |
2 | 不適合的shell命令 |
126 | 命令不可執(zhí)行 |
127 | 沒找到命令 |
128 | 無效的退出參數(shù) |
128+x | 與Linux信號x相關(guān)的嚴重錯誤 |
130 | 通過Ctrl+C終止的命令 |
255 | 正常范圍之外的退出狀態(tài)碼 |
wsx@wsx-ubuntu:~/script_learn$ asfg
未找到 'asfg' 命令,您要輸入的是否是:
命令 'asdfg' 來自于包 'aoeui' (universe)
asfg:未找到命令
wsx@wsx-ubuntu:~/script_learn$ echo $?
127
exit命令
默認繁扎,shell腳本會以腳本最后的一個命令的退出狀態(tài)碼退出幔荒。
但是我們可以改變這種默認行為,返回自己的退出狀態(tài)碼梳玫。exit命令允許在腳本結(jié)束時指定一個狀態(tài)退出碼爹梁。
wsx@wsx-ubuntu:~/script_learn$ cat test13
#!/bin/bash
# testing the exit status
var1=10
var2=30
var3=$[$var1 + $var2]
echo The answer is $var3
exit 5
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test13
wsx@wsx-ubuntu:~/script_learn$ ./test13
The answer is 40
wsx@wsx-ubuntu:~/script_learn$ echo $?
5
注意最大255,如果大于它提澎,得到的是求模的結(jié)果(余數(shù))姚垃。