本篇中,我們會讨論控制流(根據使用者輸入的資訊、計算的結果,或者一個變量的目前值選擇不同的動作行為)和循環(自動重複執行任務),接着應用我們目前所學東西來編寫一個簡單的 shell 腳本,這個腳本會顯示作業系統類型、主機名、核心版本、版本号和機器硬體架構。
這個例子盡管很基礎,但是會幫助我們證明,比起使用一般的 bash 工具,我們通過發揮 python 面向對象的特性來編寫 shell 腳本會更簡單些。
換句話說,我們想從這裡出發:
<code># uname -snrvm</code>
檢查 linux 的主機名
到
用 python 腳本來檢查 linux 的主機名
或者
用腳本檢查 linux 系統資訊
看着不錯,不是嗎?那我們就挽起袖子,開幹吧。
<a target="_blank"></a>
如我們剛說那樣,控制流允許我們根據一個給定的條件,選擇不同的輸出結果。在 python 中最簡單的實作就是一個 <code>if</code>/<code>else</code> 語句。
基本文法是這樣的:
<code>if 條件:</code>
<code># 動作 1</code>
<code>else:</code>
<code># 動作 2</code>
當“條件”求值為真(true),下面的代碼塊就會被執行(<code># 動作 1</code>代表的部分)。否則,else 下面的代碼就會運作。 “條件”可以是任何表達式,隻要可以求得值為真或者假。
舉個例子:
<code>1 < 3</code> # 真
<code>firstname == "gabriel"</code> # 對 firstname 為 gabriel 的人是真,對其他不叫 gabriel 的人為假
在第一個例子中,我們比較了兩個值,判斷 1 是否小于 3。
在第二個例子中,我們比較了 firstname(一個變量)與字元串 “gabriel”,看在目前執行的位置,firstname 的值是否等于該字元串。
條件和 else 表達式都必須跟着一個冒号(<code>:</code>)。
縮進在 python 中非常重要。同樣縮進下的行被認為是相同的代碼塊。
簡單來說,一個循環就是一組指令或者表達式序列,可以按順序一直執行,隻要條件為真,或者對清單裡每個項目執行一一次。
python 中最簡單的循環,就是用 for 循環疊代一個給定清單的元素,或者對一個字元串從第一個字元開始到執行到最後一個字元結束。
基本語句:
<code>for x in example:</code>
<code># do this</code>
這裡的 example 可以是一個清單或者一個字元串。如果是清單,變量 x 就代表清單中每個元素;如果是字元串,x 就代表字元串中每個字元。
<code>>>> rockbands = []</code>
<code>>>> rockbands.append("roxette")</code>
<code>>>> rockbands.append("guns n' roses")</code>
<code>>>> rockbands.append("u2")</code>
<code>>>> for x in rockbands:</code>
<code>print(x)</code>
<code>或</code>
<code>>>> firstname = "gabriel"</code>
<code>>>> for x in firstname:</code>
上面例子的輸出如下圖所示:
學習 python 中的循環
很明顯,必須有個辦法将一系列的 python 指令和表達式儲存到檔案裡,然後在需要的時候取出來。
準确來說子產品就是這樣的。比如,os 子產品提供了一個到作業系統的底層的接口,可以允許我們做許多通常在指令行下執行的操作。
沒錯,os 子產品包含了許多可以用來調用的方法和屬性,就如我們之前文章裡講解的那樣。不過,我們需要使用<code>import</code> 關鍵詞導入(或者叫包含)子產品到運作環境裡來:
<code>>>> import os</code>
我們來列印出目前的工作目錄:
<code>>>> os.getcwd()</code>
學習 python 子產品
現在,讓我們把這些結合在一起(包括之前文章裡讨論的概念),編寫需要的腳本。
以一段聲明文字開始一個腳本是個不錯的想法,它可以表明腳本的目的、釋出所依據的許可證,以及一個列出做出的修改的修訂曆史。盡管這主要是個人喜好,但這會讓我們的工作看起來比較專業。
這裡有個腳本,可以輸出這篇文章最前面展示的那樣。腳本做了大量的注釋,可以讓大家可以了解發生了什麼。
在進行下一步之前,花點時間來了解它。注意,我們是如何使用一個 <code>if</code>/<code>else</code> 結構,判斷每個字段标題的長度是否比字段本身的值還大。
基于比較結果,我們用空字元去填充一個字段标題和下一個之間的空格。同時,我們使用一定數量的短線作為字段标題與其值之間的分割符。
<code>#!/usr/bin/python3</code>
<code># 如果你沒有安裝 python 3 ,那麼修改這一行為 #!/usr/bin/python</code>
<code></code>
<code># script name: uname.py</code>
<code># purpose: illustrate python oop capabilities to write shell scripts more easily</code>
<code># license: gpl v3 (http://www.gnu.org/licenses/gpl.html)</code>
<code># copyright (c) 2016 gabriel alejandro cánepa</code>
<code># facebook / skype / g+ / twitter / github: gacanepa</code>
<code># email: gacanepa (at) gmail (dot) com</code>
<code># this program is free software: you can redistribute it and/or modify</code>
<code># it under the terms of the gnu general public license as published by</code>
<code># the free software foundation, either version 3 of the license, or</code>
<code># (at your option) any later version.</code>
<code># this program is distributed in the hope that it will be useful,</code>
<code># but without any warranty; without even the implied warranty of</code>
<code># merchantability or fitness for a particular purpose. see the</code>
<code># gnu general public license for more details.</code>
<code># you should have received a copy of the gnu general public license</code>
<code># along with this program. if not, see .</code>
<code># revision history</code>
<code># date version author change description</code>
<code># ---------- ------- --------------</code>
<code># 2016-05-28 1.0 gabriel cánepa initial version</code>
<code>### 導入 os 子產品</code>
<code>import os</code>
<code>### 将 os.uname() 的輸出指派給 systeminfo 變量</code>
<code>### os.uname() 會傳回五個字元串元組(sysname, nodename, release, version, machine)</code>
<code>### 參見文檔:https://docs.python.org/3.2/library/os.html#module-os</code>
<code>systeminfo = os.uname()</code>
<code>### 這是一個固定的數組,用于描述腳本輸出的字段标題</code>
<code>headers = ["operating system","hostname","release","version","machine"]</code>
<code>### 初始化索引值,用于定義每一步疊代中</code>
<code>### systeminfo 和字段标題的索引</code>
<code>index = 0</code>
<code>### 字段标題變量的初始值</code>
<code>caption = ""</code>
<code>### 值變量的初始值</code>
<code>values = ""</code>
<code>### 分隔線變量的初始值</code>
<code>separators = ""</code>
<code>### 開始循環</code>
<code>for item in systeminfo:</code>
<code>if len(item) < len(headers[index]):</code>
<code>### 一個包含橫線的字元串,橫線長度等于item[index] 或 headers[index]</code>
<code>### 要重複一個字元,用引号圈起來并用星号(*)乘以所需的重複次數</code>
<code>separators = separators + "-" * len(headers[index]) + " "</code>
<code>caption = caption + headers[index] + " "</code>
<code>values = values + systeminfo[index] + " " * (len(headers[index]) - len(item)) + " "</code>
<code>separators = separators + "-" * len(item) + " "</code>
<code>caption = caption + headers[index] + " " * (len(item) - len(headers[index]) + 1)</code>
<code>values = values + item + " "</code>
<code>### 索引加 1</code>
<code>index = index + 1</code>
<code>### 終止循環</code>
<code>### 輸出轉換為大寫的變量(字段标題)名</code>
<code>print(caption.upper())</code>
<code>### 輸出分隔線</code>
<code>print(separators)</code>
<code># 輸出值(systeminfo 中的項目)</code>
<code>print(values)</code>
<code>### 步驟:</code>
<code>### 1) 保持該腳本為 uname.py (或任何你想要的名字)</code>
<code>### 并通過如下指令給其執行權限:</code>
<code>### chmod +x uname.py</code>
<code>### 2) 執行它;</code>
<code>### ./uname.py</code>
如果你已經按照上述描述将上面的腳本儲存到一個檔案裡,并給檔案增加了執行權限,那麼運作它:
<code># chmod +x uname.py</code>
<code># ./uname.py</code>
如果試圖運作腳本時你得到了如下的錯誤:
<code>-bash: ./uname.py: /usr/bin/python3: bad interpreter: no such file or directory</code>
這意味着你沒有安裝 python3。如果那樣的話,你要麼安裝 python3 的包,要麼替換解釋器那行(如果如之前文章裡概述的那樣,跟着下面的步驟去更新 python 執行檔案的軟連接配接,要特别注意并且非常小心):
為
<code>#!/usr/bin/python</code>
這樣會通過使用已經安裝好的 python 2 去執行該腳本。
注意:該腳本在 python 2.x 與 pyton 3.x 上都測試成功過了。
盡管比較粗糙,你可以認為該腳本就是一個 python 子產品。這意味着你可以在 idle 中打開它(file → open… → select file):
在 idle 中打開 python
一個包含有檔案内容的新視窗就會打開。然後執行 run → run module(或者按 f5)。腳本的輸出就會在原始的 shell 裡顯示出來:
執行 python 腳本
另外,在所有的 linux 系統版本中都至少內建了一個 python 版本(2.x 或者 3.x,或者兩者都有)。你還需要依賴 shell 去完成同樣的目标嗎?那樣你可能需要為不同的 shell 編寫不同的版本。
這裡示範了面向對象程式設計的特性,它會成為一個系統管理者得力的助手。
這篇文章裡,我們講解了 python 中控制流、循環/疊代、和子產品的概念。我們也示範了如何利用 python 中面向對象程式設計的方法和屬性來簡化複雜的 shell 腳本。
原文釋出時間為:2016-08-19
本文來自雲栖社群合作夥伴“linux中國”