通常,當(dāng)人們提到“shell腳本語(yǔ)言”時(shí),浮現(xiàn)在他們腦海中是bash,ksh,sh或者其它相類(lèi)似的linux/unix腳本語(yǔ)言。腳本語(yǔ)言是與計(jì)算機(jī)交流的另外一種途徑。使用圖形化窗口界面(不管是windows還是linux都無(wú)所謂)用戶(hù)可以移動(dòng)鼠標(biāo)并點(diǎn)擊各種對(duì)象,比如按鈕、列表、選框等等。但這種方式在每次用戶(hù)想要計(jì)算機(jī)/服務(wù)器完成相同任務(wù)時(shí)(比如說(shuō)批量轉(zhuǎn)換照片,或者下載新的電影、mp3等)卻是十分不方便。要想讓所有這些事情變得簡(jiǎn)單并且自動(dòng)化,我們可以使用shell腳本。
某些編程語(yǔ)言,像pascal、foxpro、C、java之類(lèi),在執(zhí)行前需要先進(jìn)行編譯。它們需要合適的編譯器來(lái)讓我們的代碼完成某個(gè)任務(wù)。
而其它一些編程語(yǔ)言,像php、javascript、visualbasic之類(lèi),則不需要編譯器,因此它們需要解釋器,而我們不需要編譯代碼就可以運(yùn)行程序。
shell腳本也像解釋器一樣,但它通常用于調(diào)用外部已編譯的程序。然后,它會(huì)捕獲輸出結(jié)果、退出代碼并根據(jù)情況進(jìn)行處理。
Linux世界中最為流行的shell腳本語(yǔ)言之一,就是bash。而我認(rèn)為(這是我自己的看法)原因在于,默認(rèn)情況下bash shell可以讓用戶(hù)便捷地通過(guò)歷史命令(先前執(zhí)行過(guò)的)導(dǎo)航,與之相反的是,ksh則要求對(duì).profile進(jìn)行一些調(diào)整,或者記住一些“魔術(shù)”組合鍵來(lái)查閱歷史并修正命令。
好了,我想這些介紹已經(jīng)足夠了,剩下來(lái)哪個(gè)環(huán)境最適合你,就留給你自己去判斷吧。從現(xiàn)在開(kāi)始,我將只講bash及其腳本。在下面的例子中,我將使用CentOS 6.6和bash-4.1.2。請(qǐng)確保你有相同版本,或者更高版本。
Shell腳本流
shell腳本語(yǔ)言就跟和幾個(gè)人聊天類(lèi)似。你只需把所有命令想象成能幫你做事的那些人,只要你用正確的方式來(lái)請(qǐng)求他們?nèi)プ觥1热缯f(shuō),你想要寫(xiě)文檔。首先,你需要紙。然后,你需要把內(nèi)容說(shuō)給某個(gè)人聽(tīng),讓他幫你寫(xiě)。最后,你想要把它存放到某個(gè)地方。或者說(shuō),你想要造一所房子,因而你需要請(qǐng)合適的人來(lái)清空?qǐng)龅?。在他們說(shuō)“事情干完了”,那么另外一些工程師就可以幫你來(lái)砌墻。最后,當(dāng)這些工程師們也告訴你“事情干完了”的時(shí)候,你就可以叫油漆工來(lái)給房子粉飾了。如果你讓油漆工在墻砌好前就來(lái)粉飾,會(huì)發(fā)生什么呢?我想,他們會(huì)開(kāi)始發(fā)牢騷了。幾乎所有這些像人一樣的命令都會(huì)說(shuō)話,如果它們完成了工作而沒(méi)有發(fā)生什么問(wèn)題,那么它們就會(huì)告訴“標(biāo)準(zhǔn)輸出”。如果它們不能做你叫它們做的事——它們會(huì)告訴“標(biāo)準(zhǔn)錯(cuò)誤”。這樣,最后,所有的命令都通過(guò)“標(biāo)準(zhǔn)輸入”來(lái)聽(tīng)你的話。
快速實(shí)例——當(dāng)你打開(kāi)linux終端并寫(xiě)一些文本時(shí)——你正通過(guò)“標(biāo)準(zhǔn)輸入”和bash說(shuō)話。那么,讓我們來(lái)問(wèn)問(wèn)bash shell who am i(我是誰(shuí)?)吧。
復(fù)制代碼 代碼如下:
root@localhost ~]# who am i --- 你通過(guò)標(biāo)準(zhǔn)輸入對(duì) bash shell 說(shuō)
root pts/0 2015-04-22 20:17 (192.168.1.123) --- bash shell通過(guò)標(biāo)準(zhǔn)輸出回答你
現(xiàn)在,讓我們說(shuō)一些bash聽(tīng)不懂的問(wèn)題:
復(fù)制代碼 代碼如下:
[root@localhost ~]# blablabla --- 哈,你又在和標(biāo)準(zhǔn)輸入說(shuō)話了
-bash: blablabla: command not found --- bash通過(guò)標(biāo)準(zhǔn)錯(cuò)誤在發(fā)牢騷了
“:”之前的第一個(gè)單詞通常是向你發(fā)牢騷的命令。實(shí)際上,這些流中的每一個(gè)都有它們自己的索引號(hào)(LCTT 譯注:文件句柄號(hào)):
●標(biāo)準(zhǔn)輸入(stdin) - 0
●標(biāo)準(zhǔn)輸出(stdout) - 1
●標(biāo)準(zhǔn)錯(cuò)誤(stderr) - 2
如果你真的想要知道哪個(gè)輸出命令說(shuō)了些什么——你需要將那次發(fā)言重定向到(在命令后使用大于號(hào)“>”和流索引)文件:
復(fù)制代碼 代碼如下:
[root@localhost ~]# blablabla 1> output.txt
-bash: blablabla: command not found
在本例中,我們?cè)囍囟ㄏ蛄?(stdout)到名為output.txt的文件。讓我們來(lái)看對(duì)該文件內(nèi)容所做的事情吧,使用cat命令可以做這事:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat output.txt
[root@localhost ~]#
看起來(lái)似乎是空的。好吧,現(xiàn)在讓我們來(lái)重定向流2(stderr):
復(fù)制代碼 代碼如下:
[root@localhost ~]# blablabla 2> error.txt
[root@localhost ~]#
好吧,我們看到牢騷話沒(méi)了。讓我們檢查一下那個(gè)文件:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat error.txt
-bash: blablabla: command not found
[root@localhost ~]#
果然如此!我們看到,所有牢騷話都被記錄到errors.txt文件里頭去了。
有時(shí)候,命令會(huì)同時(shí)產(chǎn)生stdout和stderr。要重定向它們到不同的文件,我們可以使用以下語(yǔ)句:
command 1>out.txt 2>err.txt
要縮短一點(diǎn)語(yǔ)句,我們可以忽略“1”,因?yàn)槟J(rèn)情況下stdout會(huì)被重定向:
command >out.txt 2>err.txt好吧,讓我們?cè)囋囎鲂皦氖隆薄W屛覀冇胷m命令把file1和folder1給刪了吧:
復(fù)制代碼 代碼如下:
[root@localhost ~]# rm -vf folder1 file1 > out.txt 2>err.txt
現(xiàn)在來(lái)檢查以下輸出文件:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat out.txt
removed `file1'
[root@localhost ~]# cat err.txt
rm: cannot remove `folder1': Is a directory
[root@localhost ~]#
正如我們所看到的,不同的流被分離到了不同的文件。有時(shí)候,這也不是很方便,因?yàn)槲覀兿胍榭闯霈F(xiàn)錯(cuò)誤時(shí),在某些操作前面或后面所連續(xù)發(fā)生的事情。要實(shí)現(xiàn)這一目的,我們可以重定向兩個(gè)流到同一個(gè)文件:
command >>out_err.txt 2>>out_err.txt
注意:請(qǐng)注意,我使用“>>”替代了“>”。它允許我們附加到文件,而不是覆蓋文件。
我們也可以重定向一個(gè)流到另一個(gè):
command >out_err.txt 2>1
讓我來(lái)解釋一下吧。所有命令的標(biāo)準(zhǔn)輸出將被重定向到out_err.txt,錯(cuò)誤輸出將被重定向到流1(上面已經(jīng)解釋過(guò)了),而該流會(huì)被重定向到同一個(gè)文件。讓我們看這個(gè)實(shí)例:
復(fù)制代碼 代碼如下:
[root@localhost ~]# rm -fv folder2 file2 >out_err.txt 2>1
[root@localhost ~]# cat out_err.txt
rm: cannot remove `folder2': Is a directory
removed `file2'
[root@localhost ~]#
看著這些組合的輸出,我們可以將其說(shuō)明為:首先,rm命令試著將folder2刪除,而它不會(huì)成功,因?yàn)閘inux要求-r鍵來(lái)允許rm命令刪除文件夾,而第二個(gè)file2會(huì)被刪除。通過(guò)為rm提供-v(詳情)鍵,我們讓rm命令告訴我們每個(gè)被刪除的文件或文件夾。
這些就是你需要知道的,關(guān)于重定向的幾乎所有內(nèi)容了。我是說(shuō)幾乎,因?yàn)檫€有一個(gè)更為重要的重定向工具,它稱(chēng)之為“管道”。通過(guò)使用|(管道)符號(hào),我們通常重定向stdout流。
比如說(shuō),我們有這樣一個(gè)文本文件:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat text_file.txt
This line does not contain H e l l o word
This lilne contains Hello
This also containd Hello
This one no due to HELLO all capital
Hello bash world!
而我們需要找到其中某些帶有“Hello”的行,Linux中有個(gè)grep命令可以完成該工作:
復(fù)制代碼 代碼如下:
[root@localhost ~]# grep Hello text_file.txt
This lilne contains Hello
This also containd Hello
Hello bash world!
[root@localhost ~]#
當(dāng)我們有個(gè)文件,想要在里頭搜索的時(shí)候,這用起來(lái)很不錯(cuò)。當(dāng)如果我們需要在另一個(gè)命令的輸出中查找某些東西,這又該怎么辦呢?是的,當(dāng)然,我們可以重定向輸出到文件,然后再在文件里頭查找:
復(fù)制代碼 代碼如下:
[root@localhost ~]# fdisk -l>fdisk.out
[root@localhost ~]# grep "Disk /dev" fdisk.out
Disk /dev/sda: 8589 MB, 8589934592 bytes
Disk /dev/mapper/VolGroup-lv_root: 7205 MB, 7205814272 bytes
Disk /dev/mapper/VolGroup-lv_swap: 855 MB, 855638016 bytes
[root@localhost ~]#
如果你打算grep一些雙引號(hào)引起來(lái)帶有空格的內(nèi)容呢!
注意:fdisk命令顯示關(guān)于Linux操作系統(tǒng)磁盤(pán)驅(qū)動(dòng)器的信息。
就像我們看到的,這種方式很不方便,因?yàn)槲覀儾灰粫?huì)兒就把臨時(shí)文件空間給搞亂了。要完成該任務(wù),我們可以使用管道。它們?cè)试S我們重定向一個(gè)命令的stdout到另一個(gè)命令的stdin流:
復(fù)制代碼 代碼如下:
[root@localhost ~]# fdisk -l | grep "Disk /dev"
Disk /dev/sda: 8589 MB, 8589934592 bytes
Disk /dev/mapper/VolGroup-lv_root: 7205 MB, 7205814272 bytes
Disk /dev/mapper/VolGroup-lv_swap: 855 MB, 855638016 bytes
[root@localhost ~]#
如你所見(jiàn),我們不需要任何臨時(shí)文件就獲得了相同的結(jié)果。我們把fdisk stdout重定向到了grep stdin。
注意 : 管道重定向總是從左至右的。
還有幾個(gè)其它重定向,但是我們將把它們放在后面講。
在shell中顯示自定義信息
正如我們所知道的,通常,與shell的交流以及shell內(nèi)的交流是以對(duì)話的方式進(jìn)行的。因此,讓我們創(chuàng)建一些真正的腳本吧,這些腳本也會(huì)和我們講話。這會(huì)讓你學(xué)到一些簡(jiǎn)單的命令,并對(duì)腳本的概念有一個(gè)更好的理解。
假設(shè)我們是某個(gè)公司的總服務(wù)臺(tái)經(jīng)理,我們想要?jiǎng)?chuàng)建某個(gè)shell腳本來(lái)注冊(cè)呼叫信息:電話號(hào)碼、用戶(hù)名以及問(wèn)題的簡(jiǎn)要描述。我們打算把這些信息存儲(chǔ)到普通文本文件data.txt中,以便今后統(tǒng)計(jì)。腳本它自己就是以對(duì)話的方式工作,這會(huì)讓總服務(wù)臺(tái)的工作人員的小日子過(guò)得輕松點(diǎn)。那么,首先我們需要顯示提問(wèn)。對(duì)于顯示信息,我們可以用echo和printf命令。這兩個(gè)都是用來(lái)顯示信息的,但是printf更為強(qiáng)大,因?yàn)槲覀兛梢酝ㄟ^(guò)它很好地格式化輸出,我們可以讓它右對(duì)齊、左對(duì)齊或者為信息留出專(zhuān)門(mén)的空間。讓我們從一個(gè)簡(jiǎn)單的例子開(kāi)始吧。要?jiǎng)?chuàng)建文件,請(qǐng)使用你慣用的文本編輯器(kate,nano,vi,……),然后創(chuàng)建名為note.sh的文件,里面寫(xiě)入這些命令:
echo "Phone number ?"如何運(yùn)行/執(zhí)行腳本?
在保存文件后,我們可以使用bash命令來(lái)運(yùn)行,把我們的文件作為它的參數(shù):
復(fù)制代碼 代碼如下:
[root@localhost ~]# bash note.sh
Phone number ?
實(shí)際上,這樣來(lái)執(zhí)行腳本是很不方便的。如果不使用bash命令作為前綴來(lái)執(zhí)行,會(huì)更舒服一些。要讓腳本可執(zhí)行,我們可以使用chmod命令:
復(fù)制代碼 代碼如下:
[root@localhost ~]# ls -la note.sh
-rw-r--r--. 1 root root 22 Apr 23 20:52 note.sh
[root@localhost ~]# chmod +x note.sh
[root@localhost ~]# ls -la note.sh
-rwxr-xr-x. 1 root root 22 Apr 23 20:52 note.sh
[root@localhost ~]#
注意 : ls命令顯示了當(dāng)前文件夾內(nèi)的文件。通過(guò)添加-la鍵,它會(huì)顯示更多文件信息。
如我們所見(jiàn),在chmod命令執(zhí)行前,腳本只有讀(r)和寫(xiě)(w)權(quán)限。在執(zhí)行chmod +x后,它就獲得了執(zhí)行(x)權(quán)限。(關(guān)于權(quán)限的更多細(xì)節(jié),我會(huì)在下一篇文章中講述。)現(xiàn)在,我們只需這么來(lái)運(yùn)行:
復(fù)制代碼 代碼如下:
[root@localhost ~]# ./note.sh
Phone number ?
在腳本名前,我添加了 ./ 組合。.(點(diǎn))在unix世界中意味著當(dāng)前位置(當(dāng)前文件夾),/(斜線)是文件夾分隔符。(在Windows系統(tǒng)中,我們使用反斜線 \ 表示同樣功能)所以,這整個(gè)組合的意思是說(shuō):“從當(dāng)前文件夾執(zhí)行note.sh腳本”。我想,如果我用完整路徑來(lái)運(yùn)行這個(gè)腳本的話,你會(huì)更加清楚一些:
復(fù)制代碼 代碼如下:
[root@localhost ~]# /root/note.sh
Phone number ?
[root@localhost ~]#
它也能工作。
如果所有l(wèi)inux用戶(hù)都有相同的默認(rèn)shell,那就萬(wàn)事OK。如果我們只是執(zhí)行該腳本,默認(rèn)的用戶(hù)shell就會(huì)用于解析腳本內(nèi)容并運(yùn)行命令。不同的shell的語(yǔ)法、內(nèi)部命令等等有著一丁點(diǎn)不同,所以,為了保證我們的腳本會(huì)使用bash,我們應(yīng)該添加#!/bin/bash到文件首行。這樣,默認(rèn)的用戶(hù)shell將調(diào)用/bin/bash,而只有在那時(shí)候,腳本中的命令才會(huì)被執(zhí)行:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat note.sh
#!/bin/bash
echo "Phone number ?"
直到現(xiàn)在,我們才100%確信bash會(huì)用來(lái)解析我們的腳本內(nèi)容。讓我們繼續(xù)。
讀取輸入
在顯示信息后,腳本會(huì)等待用戶(hù)回答。有個(gè)read命令用來(lái)接收用戶(hù)的回答:
復(fù)制代碼 代碼如下:
#!/bin/bash
echo "Phone number ?"
read phone
在執(zhí)行后,腳本會(huì)等待用戶(hù)輸入,直到用戶(hù)按[ENTER]鍵結(jié)束輸入:
復(fù)制代碼 代碼如下:
[root@localhost ~]# ./note.sh
Phone number ?
12345 --- 這兒是我輸入的內(nèi)容
[root@localhost ~]#
你輸入的所有東西都會(huì)被存儲(chǔ)到變量phone中,要顯示變量的值,我們同樣可以使用echo命令:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat note.sh
#!/bin/bash
echo "Phone number ?"
read phone
echo "You have entered $phone as a phone number"
[root@localhost ~]# ./note.sh
Phone number ?
123456
You have entered 123456 as a phone number
[root@localhost ~]#
在bash shell中,一般我們使用$(美元)符號(hào)來(lái)表明這是一個(gè)變量,除了讀入到變量和其它為數(shù)不多的時(shí)候才不用這個(gè)$(將在今后說(shuō)明)。
好了,現(xiàn)在我們準(zhǔn)備添加剩下的問(wèn)題了:
復(fù)制代碼 代碼如下:
#!/bin/bash
echo "Phone number?"
read phone
echo "Name?"
read name
echo "Issue?"
read issue
[root@localhost ~]# ./note.sh
Phone number?
123
Name?
Jim
Issue?
script is not working.
[root@localhost ~]#
使用流重定向
太完美了!剩下來(lái)就是重定向所有東西到文件data.txt了。作為字段分隔符,我們將使用/(斜線)符號(hào)。
注意 : 你可以選擇任何你認(rèn)為是最好的分隔符,但是確保文件內(nèi)容不會(huì)包含這些符號(hào)在內(nèi),否則它會(huì)導(dǎo)致在文本行中產(chǎn)生額外字段。
別忘了使用“>>”來(lái)代替“>”,因?yàn)槲覀兿胍獙⑤敵鰞?nèi)容附加到文件末!
復(fù)制代碼 代碼如下:
[root@localhost ~]# tail -2 note.sh
read issue
echo "$phone/$name/$issue">>data.txt
[root@localhost ~]# ./note.sh
Phone number?
987
Name?
Jimmy
Issue?
Keybord issue.
[root@localhost ~]# cat data.txt
987/Jimmy/Keybord issue.
[root@localhost ~]#
注意 : tail命令顯示了文件的最后的n行。
搞定。讓我們?cè)賮?lái)運(yùn)行一次看看:
復(fù)制代碼 代碼如下:
[root@localhost ~]# ./note.sh
Phone number?
556
Name?
Janine
Issue?
Mouse was broken.
[root@localhost ~]# cat data.txt
987/Jimmy/Keybord issue.
556/Janine/Mouse was broken.
[root@localhost ~]#
我們的文件在增長(zhǎng),讓我們?cè)诿啃星懊婕觽€(gè)日期吧,這對(duì)于今后擺弄這些統(tǒng)計(jì)數(shù)據(jù)時(shí)會(huì)很有用。要實(shí)現(xiàn)這功能,我們可以使用date命令,并指定某種格式,因?yàn)槲也幌矚g默認(rèn)格式:
復(fù)制代碼 代碼如下:
[root@localhost ~]# date
Thu Apr 23 21:33:14 EEST 2015 ---- date命令的默認(rèn)輸出
[root@localhost ~]# date "+%Y.%m.%d %H:%M:%S"
2015.04.23 21:33:18 ---- 格式化后的輸出
有幾種方式可以讀取命令的輸出到變量,在這種簡(jiǎn)單的情況下,我們將使用`(是反引號(hào),不是單引號(hào),和波浪號(hào)~在同一個(gè)鍵位):
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat note.sh
#!/bin/bash
now=`date "+%Y.%m.%d %H:%M:%S"`
echo "Phone number?"
read phone
echo "Name?"
read name
echo "Issue?"
read issue
echo "$now/$phone/$name/$issue">>data.txt
[root@localhost ~]# ./note.sh
Phone number?
123
Name?
Jim
Issue?
Script hanging.
[root@localhost ~]# cat data.txt
2015.04.23 21:38:56/123/Jim/Script hanging.
[root@localhost ~]#
嗯…… 我們的腳本看起來(lái)有點(diǎn)丑啊,讓我們來(lái)美化一下。如果你要手動(dòng)讀取read命令,你會(huì)發(fā)現(xiàn)read命令也可以顯示一些信息。要實(shí)現(xiàn)該功能,我們應(yīng)該使用-p鍵加上信息:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat note.sh
#!/bin/bash
now=`date "+%Y.%m.%d %H:%M:%S"`
read -p "Phone number: " phone
read -p "Name: " name
read -p "Issue: " issue
echo "$now/$phone/$name/$issue">>data.txt
你可以直接從控制臺(tái)查找到各個(gè)命令的大量有趣的信息,只需輸入:man read, man echo, man date, man ……
同意嗎?它看上去是舒服多了!
復(fù)制代碼 代碼如下:
[root@localhost ~]# ./note.sh
Phone number: 321
Name: Susane
Issue: Mouse was stolen
[root@localhost ~]# cat data.txt
2015.04.23 21:38:56/123/Jim/Script hanging.
2015.04.23 21:43:50/321/Susane/Mouse was stolen
[root@localhost ~]#
光標(biāo)在消息的后面(不是在新的一行中),這有點(diǎn)意思。(LCTT 譯注:如果用 echo 命令輸出顯示的話,可以用 -n 參數(shù)來(lái)避免換行。)
循環(huán)
是時(shí)候來(lái)改進(jìn)我們的腳本了。如果用戶(hù)一整天都在接電話,如果每次都要去運(yùn)行,這豈不是很麻煩?讓我們讓這些活動(dòng)都永無(wú)止境地循環(huán)去吧:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat note.sh
#!/bin/bash
while true
do
read -p "Phone number: " phone
now=`date "+%Y.%m.%d %H:%M:%S"`
read -p "Name: " name
read -p "Issue: " issue
echo "$now/$phone/$name/$issue">>data.txt
done
我已經(jīng)交換了read phone和now=date行的位置。這是因?yàn)槲蚁胍谳斎腚娫捥?hào)碼后再獲得時(shí)間。如果我把它放在循環(huán)的首行,那么循環(huán)一次后,變量 now 就會(huì)在數(shù)據(jù)存儲(chǔ)到文件中后馬上獲得時(shí)間。而這并不好,因?yàn)橄乱淮魏艚锌赡茉?0分鐘后,甚至更晚。
復(fù)制代碼 代碼如下:
[root@localhost ~]# ./note.sh
Phone number: 123
Name: Jim
Issue: Script still not works.
Phone number: 777
Name: Daniel
Issue: I broke my monitor
Phone number: ^C
[root@localhost ~]# cat data.txt
2015.04.23 21:38:56/123/Jim/Script hanging.
2015.04.23 21:43:50/321/Susane/Mouse was stolen
2015.04.23 21:47:55/123/Jim/Script still not works.
2015.04.23 21:48:16/777/Daniel/I broke my monitor
[root@localhost ~]#
注意: 要從無(wú)限循環(huán)中退出,你可以按[Ctrl]+[C]鍵。Shell會(huì)顯示^表示 CTRL 鍵。
使用管道重定向
讓我們添加更多功能到我們的“弗蘭肯斯坦(Frankenstein)”,我想要腳本在每次呼叫后顯示某個(gè)統(tǒng)計(jì)數(shù)據(jù)。比如說(shuō),我想要查看各個(gè)號(hào)碼呼叫了我?guī)状巍?duì)于這個(gè),我們應(yīng)該cat文件data.txt:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat data.txt
2015.04.23 21:38:56/123/Jim/Script hanging.
2015.04.23 21:43:50/321/Susane/Mouse was stolen
2015.04.23 21:47:55/123/Jim/Script still not works.
2015.04.23 21:48:16/777/Daniel/I broke my monitor
2015.04.23 22:02:14/123/Jimmy/New script also not working!!!
[root@localhost ~]#
現(xiàn)在,所有輸出我們都可以重定向到cut命令,讓cut來(lái)把每行切成一塊一塊(我們使用分隔符“/”),然后打印第二個(gè)字段:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat data.txt | cut -d"/" -f2
123
321
123
777
123
[root@localhost ~]#
現(xiàn)在,我們可以把這個(gè)輸出重定向打另外一個(gè)命令sort:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat data.txt | cut -d"/" -f2|sort
123
123
123
321
777
[root@localhost ~]#
然后只留下唯一的行。要統(tǒng)計(jì)唯一條目,只需添加-c鍵到uniq命令:
復(fù)制代碼 代碼如下:
[root@localhost ~]# cat data.txt | cut -d"/" -f2 | sort | uniq -c
3 123
1 321
1 777
[root@localhost ~]#
只要把這個(gè)添加到我們的循環(huán)的最后:
復(fù)制代碼 代碼如下:
#!/bin/bash
while true
do
read -p "Phone number: " phone
now=`date "+%Y.%m.%d %H:%M:%S"`
read -p "Name: " name
read -p "Issue: " issue
echo "$now/$phone/$name/$issue">>data.txt
echo "===== We got calls from ====="
cat data.txt | cut -d"/" -f2 | sort | uniq -c
echo "--------------------------------"
done
運(yùn)行:
復(fù)制代碼 代碼如下:
[root@localhost ~]# ./note.sh
Phone number: 454
Name: Malini
Issue: Windows license expired.
===== We got calls from =====
3 123
1 321
1 454
1 777
--------------------------------
Phone number: ^C
當(dāng)前場(chǎng)景貫穿了幾個(gè)熟知的步驟:
●顯示消息
●獲取用戶(hù)輸入
●存儲(chǔ)值到文件
●處理存儲(chǔ)的數(shù)據(jù)
但是,如果用戶(hù)有點(diǎn)責(zé)任心,他有時(shí)候需要輸入數(shù)據(jù),有時(shí)候需要統(tǒng)計(jì),或者可能要在存儲(chǔ)的數(shù)據(jù)中查找一些東西呢?對(duì)于這些事情,我們需要使用switches/cases,并知道怎樣來(lái)很好地格式化輸出。這對(duì)于在shell中“畫(huà)”表格的時(shí)候很有用。
來(lái)自:Linux中國(guó)
原文:http://linoxide.com/linux-shell-script/guide-start-learning-shell-scripting-scratch/
作者: Petras Liumparas
譯文:LCTT https://linux.cn/article-5591-1.html
譯者: GOLinux
您可能感興趣的文章:- Linux命令行和shell腳本編程寶典 Richard Blum
- shell腳本編程之for語(yǔ)句、if語(yǔ)句使用介紹
- Linux shell腳本編程if語(yǔ)句的使用方法(條件判斷)
- Linux Shell腳本編程的注意事項(xiàng)
- 5個(gè)Shell腳本編程入門(mén)練習(xí)例子
- Shell腳本編程中常用的數(shù)學(xué)運(yùn)算實(shí)例
- shell腳本編程之if語(yǔ)句學(xué)習(xí)筆記
- shell腳本編程之循環(huán)語(yǔ)句學(xué)習(xí)筆記
- shell腳本編程之case語(yǔ)句學(xué)習(xí)筆記
- shell腳本編程實(shí)現(xiàn)9*9乘法表
- Linux Shell 腳本編程入門(mén)教程
- Shell腳本編程之判斷語(yǔ)句
- shell腳本編程之循環(huán)語(yǔ)句
- shell腳本編程之?dāng)?shù)組