歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> SHELL編程

Shell腳本編程初體驗

通常,當人們提到“shell腳本語言”時,浮現在他們腦海中是bash,ksh,sh或者其它相類似的linux/unix腳本語言。腳本語言是與計算機交流的另外一種途徑。使用圖形化窗口界面(不管是windows還是linux都無所謂)用戶可以移動鼠標並點擊各種對象,比如按鈕、列表、選框等等。但這種方式在每次用戶想要計算機/服務器完成相同任務時(比如說批量轉換照片,或者下載新的電影、mp3等)卻是十分不方便。要想讓所有這些事情變得簡單並且自動化,我們可以使用shell腳本。

某些編程語言,像pascal、foxpro、C、java之類,在執行前需要先進行編譯。它們需要合適的編譯器來讓我們的代碼完成某個任務。

而其它一些編程語言,像php、javascript、visualbasic之類,則不需要編譯器,因此它們需要解釋器,而我們不需要編譯代碼就可以運行程序。

shell腳本也像解釋器一樣,但它通常用於調用外部已編譯的程序。然後,它會捕獲輸出結果、退出代碼並根據情況進行處理。

Linux世界中最為流行的shell腳本語言之一,就是bash。而我認為(這是我自己的看法)原因在於,默認情況下bash shell可以讓用戶便捷地通過歷史命令(先前執行過的)導航,與之相反的是,ksh則要求對.profile進行一些調整,或者記住一些“魔術”組合鍵來查閱歷史並修正命令。

好了,我想這些介紹已經足夠了,剩下來哪個環境最適合你,就留給你自己去判斷吧。從現在開始,我將只講bash及其腳本。在下面的例子中,我將使用CentOS 6.6和bash-4.1.2。請確保你有相同版本,或者更高版本。

Linux Shell參數替換 http://www.linuxidc.com/Linux/2013-06/85356.htm

Shell for參數 http://www.linuxidc.com/Linux/2013-07/87335.htm

Linux/Unix Shell 參數傳遞到SQL腳本 http://www.linuxidc.com/Linux/2013-03/80568.htm

Shell腳本中參數傳遞方法介紹 http://www.linuxidc.com/Linux/2012-08/69155.htm

Shell腳本傳遞命令行參數 http://www.linuxidc.com/Linux/2012-01/52192.htm

Linux Shell 通配符、轉義字符、元字符、特殊字符 http://www.linuxidc.com/Linux/2014-10/108111.htm 

Shell腳本流

shell腳本語言就跟和幾個人聊天類似。你只需把所有命令想象成能幫你做事的那些人,只要你用正確的方式來請求他們去做。比如說,你想要寫文檔。首先,你需要紙。然後,你需要把內容說給某個人聽,讓他幫你寫。最後,你想要把它存放到某個地方。或者說,你想要造一所房子,因而你需要請合適的人來清空場地。在他們說“事情干完了”,那麼另外一些工程師就可以幫你來砌牆。最後,當這些工程師們也告訴你“事情干完了”的時候,你就可以叫油漆工來給房子粉飾了。如果你讓油漆工在牆砌好前就來粉飾,會發生什麼呢?我想,他們會開始發牢騷了。幾乎所有這些像人一樣的命令都會說話,如果它們完成了工作而沒有發生什麼問題,那麼它們就會告訴“標准輸出”。如果它們不能做你叫它們做的事——它們會告訴“標准錯誤”。這樣,最後,所有的命令都通過“標准輸入”來聽你的話。

快速實例——當你打開linux終端並寫一些文本時——你正通過“標准輸入”和bash說話。那麼,讓我們來問問bash shell who am i(我是誰?)吧。

  1. root@localhost ~]# who am i <---你通過標准輸入對 bash shell 說
  2. root pts/02015-04-2220:17(192.168.1.123)<--- bash shell通過標准輸出回答你

現在,讓我們說一些bash聽不懂的問題:

  1. [root@localhost ~]# blablabla <---哈,你又在和標准輸入說話了
  2. -bash: blablabla: command not found <--- bash通過標准錯誤在發牢騷了

“:”之前的第一個單詞通常是向你發牢騷的命令。實際上,這些流中的每一個都有它們自己的索引號(LCTT 譯注:文件句柄號):

  • 標准輸入(stdin) - 0
  • 標准輸出(stdout) - 1
  • 標准錯誤(stderr) - 2

如果你真的想要知道哪個輸出命令說了些什麼——你需要將那次發言重定向到(在命令後使用大於號“>”和流索引)文件:

  1. [root@localhost ~]# blablabla 1> output.txt
  2. -bash: blablabla: command not found

在本例中,我們試著重定向流1(stdout)到名為output.txt的文件。讓我們來看對該文件內容所做的事情吧,使用cat命令可以做這事:

  1. [root@localhost ~]# cat output.txt
  2. [root@localhost ~]#

看起來似乎是空的。好吧,現在讓我們來重定向流2(stderr):

  1. [root@localhost ~]# blablabla 2> error.txt
  2. [root@localhost ~]#

好吧,我們看到牢騷話沒了。讓我們檢查一下那個文件:

  1. [root@localhost ~]# cat error.txt
  2. -bash: blablabla: command not found
  3. [root@localhost ~]#

果然如此!我們看到,所有牢騷話都被記錄到errors.txt文件裡頭去了。

有時候,命令會同時產生stdoutstderr。要重定向它們到不同的文件,我們可以使用以下語句:

  1. command 1>out.txt 2>err.txt

要縮短一點語句,我們可以忽略“1”,因為默認情況下stdout會被重定向:

  1. command >out.txt 2>err.txt

好吧,讓我們試試做些“壞事”。讓我們用rm命令把file1和folder1給刪了吧:

  1. [root@localhost ~]# rm -vf folder1 file1 >out.txt 2>err.txt

現在來檢查以下輸出文件:

  1. [root@localhost ~]# cat out.txt
  2. removed `file1'
  3. [root@localhost ~]# cat err.txt
  4. rm: cannot remove `folder1': Is a directory
  5. [root@localhost ~]#

正如我們所看到的,不同的流被分離到了不同的文件。有時候,這也不是很方便,因為我們想要查看出現錯誤時,在某些操作前面或後面所連續發生的事情。要實現這一目的,我們可以重定向兩個流到同一個文件:

  1. command >>out_err.txt 2>>out_err.txt

注意:請注意,我使用“>>”替代了“>”。它允許我們附加到文件,而不是覆蓋文件。

我們也可以重定向一個流到另一個:

  1. command >out_err.txt 2>&1

讓我來解釋一下吧。所有命令的標准輸出將被重定向到out_err.txt,錯誤輸出將被重定向到流1(上面已經解釋過了),而該流會被重定向到同一個文件。讓我們看這個實例:

  1. [root@localhost ~]# rm -fv folder2 file2 >out_err.txt 2>&1
  2. [root@localhost ~]# cat out_err.txt
  3. rm: cannot remove `folder2': Is a directory
  4. removed `file2'
  5. [root@localhost ~]#

看著這些組合的輸出,我們可以將其說明為:首先,rm命令試著將folder2刪除,而它不會成功,因為linux要求-r鍵來允許rm命令刪除文件夾,而第二個file2會被刪除。通過為rm提供-v(詳情)鍵,我們讓rm命令告訴我們每個被刪除的文件或文件夾。

這些就是你需要知道的,關於重定向的幾乎所有內容了。我是說幾乎,因為還有一個更為重要的重定向工具,它稱之為“管道”。通過使用|(管道)符號,我們通常重定向stdout流。

比如說,我們有這樣一個文本文件:

  1. [root@localhost ~]# cat text_file.txt
  2. This line does not contain H e l l o word
  3. This lilne contains Hello
  4. This also containd Hello
  5. This one no due to HELLO all capital
  6. Hello bash world!

而我們需要找到其中某些帶有“Hello”的行,Linux中有個grep命令可以完成該工作:

  1. [root@localhost ~]# grep Hello text_file.txt
  2. This lilne contains Hello
  3. This also containd Hello
  4. Hello bash world!
  5. [root@localhost ~]#

當我們有個文件,想要在裡頭搜索的時候,這用起來很不錯。當如果我們需要在另一個命令的輸出中查找某些東西,這又該怎麼辦呢?是的,當然,我們可以重定向輸出到文件,然後再在文件裡頭查找:

  1. [root@localhost ~]# fdisk -l>fdisk.out
  2. [root@localhost ~]# grep "Disk /dev" fdisk.out
  3. Disk/dev/sda:8589 MB,8589934592 bytes
  4. Disk/dev/mapper/VolGroup-lv_root:7205 MB,7205814272 bytes
  5. Disk/dev/mapper/VolGroup-lv_swap:855 MB,855638016 bytes
  6. [root@localhost ~]#

如果你打算grep一些雙引號引起來帶有空格的內容呢!

注意:fdisk命令顯示關於Linux操作系統磁盤驅動器的信息。

就像我們看到的,這種方式很不方便,因為我們不一會兒就把臨時文件空間給搞亂了。要完成該任務,我們可以使用管道。它們允許我們重定向一個命令的stdout到另一個命令的stdin流:

  1. [root@localhost ~]# fdisk -l | grep "Disk /dev"
  2. Disk/dev/sda:8589 MB,8589934592 bytes
  3. Disk/dev/mapper/VolGroup-lv_root:7205 MB,7205814272 bytes
  4. Disk/dev/mapper/VolGroup-lv_swap:855 MB,855638016 bytes
  5. [root@localhost ~]#

如你所見,我們不需要任何臨時文件就獲得了相同的結果。我們把fdisk stdout重定向到了grep stdin

注意 : 管道重定向總是從左至右的。

還有幾個其它重定向,但是我們將把它們放在後面講。

在shell中顯示自定義信息

正如我們所知道的,通常,與shell的交流以及shell內的交流是以對話的方式進行的。因此,讓我們創建一些真正的腳本吧,這些腳本也會和我們講話。這會讓你學到一些簡單的命令,並對腳本的概念有一個更好的理解。

假設我們是某個公司的總服務台經理,我們想要創建某個shell腳本來注冊呼叫信息:電話號碼、用戶名以及問題的簡要描述。我們打算把這些信息存儲到普通文本文件data.txt中,以便今後統計。腳本它自己就是以對話的方式工作,這會讓總服務台的工作人員的小日子過得輕松點。那麼,首先我們需要顯示提問。對於顯示信息,我們可以用echo和printf命令。這兩個都是用來顯示信息的,但是printf更為強大,因為我們可以通過它很好地格式化輸出,我們可以讓它右對齊、左對齊或者為信息留出專門的空間。讓我們從一個簡單的例子開始吧。要創建文件,請使用你慣用的文本編輯器(kate,nano,vi,……),然後創建名為note.sh的文件,裡面寫入這些命令:

  1. echo "Phone number ?" 

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-06/118574p2.htm 

Copyright © Linux教程網 All Rights Reserved