Linux 平台下 Python 腳本編程入門(二)
本篇中,我們會討論控制流(根據用戶輸入的信息、計算的結果,或者一個變數的當前值選擇不同的動作行為)和循環(自動重複執行任務),接著應用我們目前所學東西來編寫一個簡單的 shell 腳本,這個腳本會顯示操作系統類型、主機名、內核版本、版本號和機器硬體架構。
這個例子儘管很基礎,但是會幫助我們證明,比起使用一般的 bash 工具,我們通過發揮 Python 面向對象的特性來編寫 shell 腳本會更簡單些。
換句話說,我們想從這裡出發:
# uname -snrvm
檢查 Linux 的主機名
到
用 Python 腳本來檢查 Linux 的主機名
或者
用腳本檢查 Linux 系統信息
看著不錯,不是嗎?那我們就挽起袖子,開干吧。
Python 中的控制流
如我們剛說那樣,控制流允許我們根據一個給定的條件,選擇不同的輸出結果。在 Python 中最簡單的實現就是一個 if
/else
語句。
基本語法是這樣的:
if 條件:
# 動作 1
else:
# 動作 2
當「條件」求值為真(true),下面的代碼塊就會被執行(# 動作 1
代表的部分)。否則,else 下面的代碼就會運行。 「條件」可以是任何表達式,只要可以求得值為真或者假。
舉個例子:
1 < 3
# 真firstName == "Gabriel"
# 對 firstName 為 Gabriel 的人是真,對其他不叫 Gabriel 的人為假
- 在第一個例子中,我們比較了兩個值,判斷 1 是否小於 3。
- 在第二個例子中,我們比較了 firstName(一個變數)與字元串 「Gabriel」,看在當前執行的位置,firstName 的值是否等於該字元串。
- 條件和 else 表達式都必須跟著一個冒號(
:
)。 - 縮進在 Python 中非常重要。同樣縮進下的行被認為是相同的代碼塊。
請注意,if
/else
表達式只是 Python 中許多控制流工具的一個而已。我們先在這裡了解以下,後面會用在我們的腳本中。你可以在官方文檔中學到更多工具。
Python 中的循環
簡單來說,一個循環就是一組指令或者表達式序列,可以按順序一直執行,只要條件為真,或者對列表裡每個項目執行一一次。
Python 中最簡單的循環,就是用 for 循環迭代一個給定列表的元素,或者對一個字元串從第一個字元開始到執行到最後一個字元結束。
基本語句:
for x in example:
# do this
這裡的 example 可以是一個列表或者一個字元串。如果是列表,變數 x 就代表列表中每個元素;如果是字元串,x 就代表字元串中每個字元。
>>> rockBands = []
>>> rockBands.append("Roxette")
>>> rockBands.append("Guns N' Roses")
>>> rockBands.append("U2")
>>> for x in rockBands:
print(x)
或
>>> firstName = "Gabriel"
>>> for x in firstName:
print(x)
上面例子的輸出如下圖所示:
學習 Python 中的循環
Python 模塊
很明顯,必須有個辦法將一系列的 Python 指令和表達式保存到文件里,然後在需要的時候取出來。
準確來說模塊就是這樣的。比如,os 模塊提供了一個到操作系統的底層的介面,可以允許我們做許多通常在命令行下執行的操作。
沒錯,os 模塊包含了許多可以用來調用的方法和屬性,就如我們之前文章里講解的那樣。不過,我們需要使用 import
關鍵詞導入(或者叫包含)模塊到運行環境里來:
>>> import os
我們來列印出當前的工作目錄:
>>> os.getcwd()
學習 Python 模塊
現在,讓我們把這些結合在一起(包括之前文章里討論的概念),編寫需要的腳本。
Python 腳本
以一段聲明文字開始一個腳本是個不錯的想法,它可以表明腳本的目的、發布所依據的許可證,以及一個列出做出的修改的修訂歷史。儘管這主要是個人喜好,但這會讓我們的工作看起來比較專業。
這裡有個腳本,可以輸出這篇文章最前面展示的那樣。腳本做了大量的注釋,可以讓大家可以理解發生了什麼。
在進行下一步之前,花點時間來理解它。注意,我們是如何使用一個 if
/else
結構,判斷每個欄位標題的長度是否比欄位本身的值還大。
基於比較結果,我們用空字元去填充一個欄位標題和下一個之間的空格。同時,我們使用一定數量的短線作為欄位標題與其值之間的分割符。
#!/usr/bin/python3
# 如果你沒有安裝 Python 3 ,那麼修改這一行為 #!/usr/bin/python
# Script name: uname.py
# Purpose: Illustrate Python OOP capabilities to write shell scripts more easily
# License: GPL v3 (http://www.gnu.org/licenses/gpl.html)
# Copyright (C) 2016 Gabriel Alejandro Cánepa
# Facebook / Skype / G+ / Twitter / Github: gacanepa
# Email: gacanepa (at) gmail (dot) com
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# REVISION HISTORY
# DATE VERSION AUTHOR CHANGE DESCRIPTION
# ---------- ------- -----------# 2016-05-28 1.0 Gabriel Cánepa Initial version
### 導入 os 模塊
import os
### 將 os.uname() 的輸出賦值給 systemInfo 變數
### os.uname() 會返回五個字元串元組(sysname, nodename, release, version, machine)
### 參見文檔:https://docs.python.org/3.2/library/os.html#module-os
systemInfo = os.uname()
### 這是一個固定的數組,用於描述腳本輸出的欄位標題
headers = ["Operating system","Hostname","Release","Version","Machine"]
### 初始化索引值,用於定義每一步迭代中
### systemInfo 和欄位標題的索引
index = 0
### 欄位標題變數的初始值
caption = ""
### 值變數的初始值
values = ""
### 分隔線變數的初始值
separators = ""
### 開始循環
for item in systemInfo:
if len(item) < len(headers[index]):
### 一個包含橫線的字元串,橫線長度等於item[index] 或 headers[index]
### 要重複一個字元,用引號圈起來並用星號(*)乘以所需的重複次數
separators = separators + "-" * len(headers[index]) + " "
caption = caption + headers[index] + " "
values = values + systemInfo[index] + " " * (len(headers[index]) - len(item)) + " "
else:
separators = separators + "-" * len(item) + " "
caption = caption + headers[index] + " " * (len(item) - len(headers[index]) + 1)
values = values + item + " "
### 索引加 1
index = index + 1
### 終止循環
### 輸出轉換為大寫的變數(欄位標題)名
print(caption.upper())
### 輸出分隔線
print(separators)
# 輸出值(systemInfo 中的項目)
print(values)
### 步驟:
### 1) 保持該腳本為 uname.py (或任何你想要的名字)
### 並通過如下命令給其執行許可權:
### chmod +x uname.py
### 2) 執行它;
### ./uname.py
如果你已經按照上述描述將上面的腳本保存到一個文件里,並給文件增加了執行許可權,那麼運行它:
# chmod +x uname.py
# ./uname.py
如果試圖運行腳本時你得到了如下的錯誤:
-bash: ./uname.py: /usr/bin/python3: bad interpreter: No such file or directory
這意味著你沒有安裝 Python3。如果那樣的話,你要麼安裝 Python3 的包,要麼替換解釋器那行(如果如之前文章里概述的那樣,跟著下面的步驟去更新 Python 執行文件的軟連接,要特別注意並且非常小心):
#!/usr/bin/python3
為
#!/usr/bin/python
這樣會通過使用已經安裝好的 Python 2 去執行該腳本。
注意:該腳本在 Python 2.x 與 Pyton 3.x 上都測試成功過了。
儘管比較粗糙,你可以認為該腳本就是一個 Python 模塊。這意味著你可以在 IDLE 中打開它(File → Open… → Select file):
在 IDLE 中打開 Python
一個包含有文件內容的新窗口就會打開。然後執行 Run → Run module(或者按 F5)。腳本的輸出就會在原始的 Shell 里顯示出來:
執行 Python 腳本
如果你想純粹用 bash 寫一個腳本,也獲得同樣的結果,你可能需要結合使用 awk、sed,並且藉助複雜的方法來存儲與獲得列表中的元素(不要忘了使用 tr 命令將小寫字母轉為大寫)。
另外,在所有的 Linux 系統版本中都至少集成了一個 Python 版本(2.x 或者 3.x,或者兩者都有)。你還需要依賴 shell 去完成同樣的目標嗎?那樣你可能需要為不同的 shell 編寫不同的版本。
這裡演示了面向對象編程的特性,它會成為一個系統管理員得力的助手。
注意:你可以在我的 Github 倉庫里獲得 這個 python 腳本(或者其他的)。
總結
這篇文章里,我們講解了 Python 中控制流、循環/迭代、和模塊的概念。我們也演示了如何利用 Python 中面向對象編程的方法和屬性來簡化複雜的 shell 腳本。
你有任何其他希望去驗證的想法嗎?開始吧,寫出自己的 Python 腳本,如果有任何問題可以諮詢我們。不必猶豫,在分割線下面留下評論,我們會儘快回復你。
via: http://www.tecmint.com/learn-python-programming-to-write-linux-shell-scripts/
作者:Gabriel Cánepa 譯者:wi-cuckoo 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive