この記事では、Linux システムに関するさまざまな情報を取得するための Python プログラミング言語ツールの使用について説明します。さあ行こう。
Python のバージョンはどれですか?
私が Python について言及するときは、CPython 2 (正確には 2.7) を指しますが、同じコードが CPython 3 (3.3) では動作しないことを明示し、その違いについては「代替コード」で説明します。 。 CPython がインストールされていることを確認し、ターミナルに python または python3 と入力して Enter キーを押すと、ターミナルに Python プロンプト (プロンプト) が表示されるはずです。
すべてのプログラムの最初の行に #!/usr/bin/env/python があることに注意してください。つまり、Python インタープリターにこれらのスクリプトを実行させる必要があります。したがって、スクリプトを実行可能にしたい場合は、chmod +x your-script.py を使用すると、./your-script.py を使用して実行できます (これについては、この記事で説明します)
プラットフォーム モジュールを探索する
プラットフォームモジュールは標準ライブラリに含まれており、多数のシステム情報を取得できる多くの関数を備えています。 Python インタープリターを実行して、platform.uname() 関数から始めて、それらのいくつかを調べてみましょう:
Linux の uname コマンドをすでに知っている場合は、この関数がこのコマンドへのインターフェイスであることがわかるでしょう。 Python 2 では、システム タイプ (またはカーネル バージョン)、ホスト名、バージョン、リリース バージョン、マシン ハードウェア、およびプロセッサ情報を含むタプルを返します。次のように添え字を使用して個々のプロパティにアクセスできます:
uname_result(system='Linux', node='fedora.echorand',
release='3.7.4-204.fc18.x86_64'、version='#1 SMP 水曜日 1 月 23 日 16:44:29
UTC 2013'、マシン='x86_64'、プロセッサ='x86_64')
結果は名前付きタプルであるため、次のように添え字を覚える必要がなく、名前だけで特定のプロパティを指定することができます。
プラットフォーム モジュールには、次のような上記の属性の一部への直接インターフェイスもあります。
>>>platform.release()
'3.7.4-204.fc18.x86_64'
linux_distribution() 関数は、使用している Linux ディストリビューションのバージョンに関する詳細情報を返します。たとえば、Fedora 18 システムでは、このコマンドは次の情報を返します:
この返される結果には、バージョン リリース名、バージョン、コードネームのタプルが含まれています。特定の Python バージョンでサポートされているディストリビューションは、_supported_dists に示されている値を介して取得できます。
お使いの Linux ディストリビューションがそれら (またはその派生製品の 1 つ) に含まれていない場合。その場合、上記の関数を呼び出しても、有益な情報が表示されない可能性があります。
プラットフォーム モジュールの最後の関数である、architecture() 関数を見ていきます。引数なしでこの関数を呼び出すと、次のようなアーキテクチャ ビットと Python 実行可能形式を含むタプルが返されます。
これら以外にもプラットフォーム モジュールの他の機能を調べて、現在実行している Python のバージョンを確認することをお勧めします。このモジュールがこの情報をどのように取得するかを知りたい場合は、PYthon ソース ディレクトリの Lib/platform.py ファイルを詳しく調べることができます。
os および sys モジュールは、ネイティブ エンディアンなどの一部のシステム プロパティを取得することもできます。次に、Python 標準ライブラリ モジュールを超えて、proc および sysfs ファイル システムを通じて Linux システムの情報にアクセスできるようにするいくつかの機能を検討します。ファイル システムを介した情報へのアクセスは、ハードウェア アーキテクチャによって異なることに注意してください。したがって、この記事を読むとき、またはスクリプトを作成するときは、これらのファイルから情報を取得できることを常に念頭に置いてください。
CPU 情報の取得
/proc/cpuinfo ファイルには、システムのプロセッサ ユニットに関する情報が含まれています。たとえば、Python バージョンの Linux コマンド cat /proc/cpuinfo の動作は次のとおりです:
__future__ から print_function をインポート
open('/proc/cpuinfo') を f:
として使用
f の行:
print(line.rstrip('n'))
Python 2 または Python 3 を使用してこのプログラムを実行すると、/proc/cpuinfo のすべての内容が画面に表示されます (上記のプログラムでは、rstrip() メソッドを使用して末尾の改行文字が削除されています)各行の)
以下のコードは、startwith() 文字列メソッドを使用してプロセッサ ユニットのモードを表示する方法を示しています。
"""
のモデルを印刷します
処理ユニット
"""
__future__ から print_function をインポート
open('/proc/cpuinfo') を f:
として使用
f の行:
#
の間の情報を区切る空行を無視します。
# 2 つの処理ユニットの詳細
if line.strip():
If line.rstrip('n').startswith('モデル名'):
モデル名 = line.rstrip('n').split(':')[1]
印刷(モデル名)
このプログラムを実行すると、各プロセッサーユニットのモード名が表示されるはずです。たとえば、これが私のコンピューター上に表示されるものです。
これまで、使用しているシステムのアーキテクチャを確認する方法は 2 つありました。技術的には正しく、どちらの方法も実際にはシステムが実行されているカーネル アーキテクチャを報告するため、コンピュータが 64 ビットであっても 32 ビット カーネルを実行している場合、上記の方法では引き続き「32 ビット アーキテクチャの場合」と表示されます。 /proc/cpuinfo にリストされているフラグから lm フラグを探すことで、コンピュータの実際のアーキテクチャを見つけることができます。 lm フラグはロング モードを表し、64 ビット アーキテクチャでのみ表示されます。次の手順でその方法を説明します:
""" リアルビットアーキテクチャを見つける
"""
__future__ から print_function をインポート
open('/proc/cpuinfo') を f:
として使用
f の行:
#
の間の情報を区切る空行を無視します。
# 2 つの処理ユニットの詳細
if line.strip():
if line.rstrip('n').startswith('flags')
または line.rstrip('n').startswith('特徴'):
line.rstrip('n').split() の 'lm' の場合:
Print('64 ビット')
その他:
Print('32 ビット')
これまで見てきたように、/proc/cpuinfo ファイルを読み取り、単純なテキスト処理手法を使用することで、探しているデータを取得できます。他のプログラムがこのデータをより適切に使用できるようにするには、/proc/cpuinfo の内容を辞書などの標準データ構造にすることをお勧めします。注は単純です。このファイルの内容を見ると、各プロセッサ ユニットにいくつかのキーと値のペアがあることがわかります (前の例では、各プロセッサのモデル名を出力しました。これがモデルです)名前がキーワードです)。異なるプロセッサユニットの情報は空行で区切ることができます。各プロセッサユニットのキーを含む辞書データ構造を構築するのは簡単です。各キーワードのプロセッサ ユニットの値は /proc/cpuinfo ファイルにあります。以下のコードは、これを行う方法について説明します。
"""
Python 辞書としての /proc/cpuinfo
"""
from __future__ import print_function
コレクションからのインポート OrderedDict
pprint をインポート
def cpuinfo():
'' /proc/cpuinfo
の情報を返します
次の形式の辞書として:
cpu_info['proc0']={...}
cpu_info['proc1']={...}
''
cpuinfo=OrderedDict()
procinfo=OrderedDict()
nprocs = 0
open('/proc/cpuinfo') を f:
として使用
f の行:
line.strip():
でない場合
# 1 つのプロセッサの終わり
cpuinfo['proc%s' % nprocs] = procinfo
nprocs=nprocs+1
# リセット
procinfo=OrderedDict()
その他:
len(line.split(':')) == 2の場合:
procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip()
その他:
procinfo[line.split(':')[0].strip()] = ''
cpuinfo
を返します
cpuinfo = cpuinfo()
cpuinfo.keys() のプロセッサ用:
print(cpuinfo[プロセッサ]['モデル名'])
このコードは、通常の辞書の代わりに OrderedDict (順序付き辞書) を使用します。これは、キー値を使用して順序どおりにファイルに保存できます。したがって、最初のプロセッサ ユニットからのデータの後に 2 番目のプロセッサ ユニットからのデータが続き、以下同様になります。フィルターを使用して、探している情報をフィルター処理できます (if __name__ == '__main__' ブロックで説明されているように)。上記のプログラムは、各実行後に各プロセッサーユニットのモデル名を出力します (cpuinfo[processor]['model name'] ステートメントで示されているように)
メモリ情報の取得
/proc/cpuinfo と同様に、ファイル /proc/meminfo にはコンピュータのメイン メモリに関する情報が含まれています。以下のプログラムは、このファイルの内容が入力された辞書を作成します。
__future__ から print_function をインポート
コレクションからのインポート OrderedDict
def meminfo():
'' /proc/meminfo
の情報を返します
辞書として ''
Meminfo=OrderedDict()
with open('/proc/meminfo') as f:
f の行:
meminfo[line.split(':')[0]] = line.split(':')[1].strip()
meminfo
if __name__=='__main__':
#print(meminfo())
Meminfo = meminfo()
Print('総メモリ: {0}'.format(meminfo['MemTotal']))
Print('空きメモリ: {0}'.format(meminfo['MemFree']))
以前と同様に、キーワード (if __name__==__main__ ブロックで表される) を通じてクエリする特定の情報にアクセスできます。このプログラムを実行すると、次のような出力が表示されるはずです:
ネットワーク統計
次に、コンピューター システムのネットワーク機器を調べます。システムの再起動後に、システムのネットワーク インターフェイスと、それらを介したデータの送受信に関する情報を取得します。 /proc/net/dev ファイルにより、この情報が利用可能になります。このファイルの内容を調べると、最初の 1 ~ 2 行にヘッダー情報などが含まれていることがわかります。このファイルの最初の列はネットワーク インターフェイス名で、2 番目と 3 番目の列は受信したバイト数と、送信されました (たとえば、送信された合計バイト数、パケット数、エラーなど)。ここで注目したいのは、さまざまなネットワーク デバイスが送信データと受信データの合計を抽出するということです。以下のコードは、/proc/net/dev ファイルからこの情報を抽出する方法を示しています。
def netdevs():
'' 各ネットワーク デバイスの RX および TX バイト ''
with open('/proc/net/dev') as f:
net_dump = f.readlines()
device_data={}
データ =namedtuple('data',['rx','tx'])
net_dump[2:]:
の行の場合
Line = line.split(':')
line[0].strip() != 'lo' の場合:
device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
float(line[1].split()[8])/(1024.0*1024.0))
device_data
if __name__=='__main__':
netdevs = netdevs()
netdevs.keys() の開発の場合:
print('{0}: {1} MiB {2} MiB'.format(dev, netdevs[dev].rx, netdevs[dev].tx))
上記のプログラムを実行すると、次の出力には、最後に再起動してからネットワーク デバイスが送受信した合計データがメガバイト単位で表示されます。
永続的なデータ ストレージ メカニズムを使用して接続し、独自のデータ使用量監視プログラムを作成できます。
プロセス情報
/proc ディレクトリには、実行中のすべてのプロセスのディレクトリが含まれます。これらのディレクトリの名前はプロセス識別子と同じです。したがって、名前として数字を使用している /proc 内のディレクトリを反復処理すると、現在実行中のすべてのプロセスのリストが取得されます。次のコードでは、 process_list() 関数は、現在実行中のすべてのプロセスの識別子のリストを返します。このプログラムを実行すると、このリストの長さがシステム上で実行されているプロセスの総数になります。
__future__ から print_function をインポート
OS をインポート
def process_list():
pids = []
os.listdir('/proc') のサブディレクトリの場合:
if subdir.isdigit():
pids.append(subdir)
PID を返す
if __name__=='__main__':
Print('実行中のプロセスの総数:: {0}'.format(len(pids)))
デバイスをブロック
次のプログラムは、sysfs 仮想ファイル システムを読み取ることによって、すべてのブロック デバイスを一覧表示します。システム上のブロック デバイスは、/sys/block ディレクトリにあります。したがって、/sys/block/sda、/sys/block/sdb などのディレクトリが存在する可能性があります。これらすべてのデバイスを取得するには、正規表現を使用して /sys/block ディレクトリをスキャンし、対象のブロック デバイスを抽出します。
sysfs
からブロックデバイスデータを読み取ります
"""
グロブをインポート
インポートリ
OS をインポート
dev_pattern = ['sd.*','mmcblk*']
nr_sectors = open(device+'/size').read().rstrip('n')
sect_size = open(device+'/queue/hw_sector_size').read().rstrip('n')
戻り値 (float(nr_sectors)*float(sect_size))/(1024.0*1024.0*1024.0)
glob.glob('/sys/block/*') 内のデバイスの場合:
dev_pattern のパターン:
if re.compile(pattern).match(os.path.basename(device)):
print('デバイス:: {0}、サイズ:: {1} GiB '.format(デバイス, サイズ(デバイス)))
detect_devs()
コマンドラインユーティリティを構築する
Linux のコマンド ライン ツールはどこにでもあります [@Lesus 注: かつて誰かがこう言いました。コマンド ラインがなければ Linux はクソです。 ] を使用すると、コマンド ライン引数を指定してプログラムのデフォルトの動作をカスタマイズできます。 argparse モジュールは、Linux コマンド ライン ユーティリティに似たインターフェイスを提供します。次のコードは、プログラムがシステム上のすべてのユーザーを取得し、(pwd 標準ライブラリ モジュールを使用して) ログイン シェルを出力する方法を示しています。
"""
__future__ から print_function をインポート
# /etc/passwd
からユーザーを取得します
def getusers():
ユーザー = pwd.getpwall()
ユーザー内のユーザー:
print('{0}:{1}'.format(user.pw_name, user.pw_shell))
if __name__=='__main__':
getusers()
このプログラムを実行すると、システム上のすべてのユーザーとそのログイン シェル名が出力されます。
ここで、アプリケーションのユーザーがシステム ユーザー (デーモン、Apache など) を表示するかどうかを選択できるようにしたいと考えています。次のように、前のコードを拡張し、argparse モジュールを初めて使用してこの機能を実装します。
"""
Linux システム上でユーザーとパスワードを操作するためのユーティリティ
"""
__future__ から print_function をインポート
インポートパスワード
argparse をインポート
OS をインポート
def read_login_defs():
uid_min = なし
uid_max = なし
os.path.exists('/etc/login.defs') の場合:
open('/etc/login.defs') を f:
として使用します。
Login_data = f.readlines()
ログインデータの行:
line.startswith('UID_MIN') の場合:
uid_min = int(line.split()[1].strip())
if line.startswith('UID_MAX'):
uid_max = int(line.split()[1].strip())
uid_min、uid_max を返す
def getusers(no_system=False):
uid_min、uid_max = read_login_defs()
uid_min = 1000
uid_max が None の場合:
uid_max = 60000
ユーザー = pwd.getpwall()
ユーザー内のユーザー:
user.pw_uid >= uid_min および user.pw_uid <= uid_max の場合:
print( '{0}:{1}'。フォーマット(user.pw_name、user.pw_shell))
その他:
print('{0}:{1}'.format(user.pw_name, user.pw_shell))
if __name__=='__main__':
parser.add_argument('--no-system', action='store_true',dest='no_system',
デフォルト = False、help='システム ユーザーを省略するように指定')
args = parser.parse_args()
Getusers(args.no_system)
--help オプションを使用して上記のプログラムを実行すると、オプションのオプションとその機能などのわかりやすいヘルプ情報が表示されます。
コードをコピー
-h、--help このヘルプ メッセージを表示して終了します
--no-system システムユーザーを省略するように指定します
上記のプログラムの使用例は次のとおりです:
コードをコピー
コードをコピー
上記のプログラムでは、argparse モジュールの使用方法を簡単に理解しました。 parser = argparse.ArgumentParser(description="User/Password Utility") ステートメントは、プログラムの動作に関するオプションの説明を含む ArgumentParser オブジェクトを作成します。
次に、パラメーターを追加します。プログラムに次のステートメント add_argument() を認識させる必要があります。
parser.add_argument('--no-system'、action='store_true'、dest='no_system'、default = False、help='システム ユーザーを省略するよう指定')。最初のメソッド パラメータは、システムがこのプログラムを呼び出すときにプログラムがこのパラメータを提供するために使用する名前です。次のパラメータ acton=store_true は、それがブール値の選択であることを示します。つまり、それが true か false かは、プログラムの特定の動作に影響します。 dest はカスタマイズ可能なパラメータであり、その値をプログラムに提供できます。この値がユーザーによって提供されない場合、この値はデフォルトで false になります。最後のパラメータプログラムによって表示されるヘルプ情報。最後に、引数は args=parser.parse_args() メソッドによって解析されます。解析メソッドが完了すると、対応する構文パラメーター option_dest を介してユーザー オプションの値を取得できます。パラメーターを構成する場合、option_dest は指定する宛先変数です。ステートメント getusers(args.no_system) は、ユーザーが指定したパラメーターの値を使用して getusers() メソッドをコールバックします。
次のプログラムは、非ブール値オプションを指定する方法を示しています。このプログラムは 6 番目のプログラムを書き直したもので、対象のネットワーク デバイスを指定するオプションが追加されています。
def netdevs(iface=None):
'' 各ネットワーク デバイスの RX および TX バイト ''
with open('/proc/net/dev') as f:
net_dump = f.readlines()
device_data={}
データ =namedtuple('data',['rx','tx'])
net_dump[2:]:
の行の場合
Line = line.split(':')
iface でない場合:
line[0].strip() != 'lo' の場合:
device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
float(line[1].split()[8])/(1024.0*1024.0))
その他:
if line[0].strip() == iface:
device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
float(line[1].split()[8])/(1024.0*1024.0))
device_data
if __name__=='__main__':
パーサー = argparse.ArgumentParser(description='ネットワーク インターフェイス使用状況モニター')
Parser.add_argument('-i','--interface', dest='iface',
Help='ネットワークインターフェース')
args = parser.parse_args()
netdevs = netdevs(iface = args.iface)
netdevs.keys() の開発の場合:
print('{0}: {1} MiB {2} MiB'.format(dev, netdevs[dev].rx, netdevs[dev].tx))
パラメータを指定せずにプログラムを実行すると、プログラムは以前のバージョンとまったく同じように動作します。その後、対象のネットワーク デバイスを指定することもできます。例:
em1: 0.0 MiB 0.0 MiB
wlan0: 146.099492073 MiB 12.9737148285 MiB
virbr1: 0.0 MiB 0.0 MiB
virbr1-nic: 0.0 MiB 0.0 MiB
$ ./net_devs_2.py --help
使用法: net_devs_2.py [-h] [-i IFACE]
ネットワークインターフェース使用状況モニター
オプションの引数:
-h、--help このヘルプ メッセージを表示して終了します
-i IFACE、--インターフェース IFACE
ネットワークインターフェース
$ ./net_devs_2.py -i wlan0
wlan0: 146.100307465 MiB 12.9777050018 MiB
システム全体でのスクリプトの可用性
この記事の助けを借りて、他の Linux コマンドと同様に、毎日使いたくなる便利なスクリプトを 1 つ以上作成できるようになったかもしれません。最も簡単な方法は、スクリプトを実行可能にし、そのスクリプトに BASH エイリアスを設定することです。 .py 拡張子を削除して、スクリプトを /usr/local/sbin などの標準の場所に配置することもできます。
その他の便利な標準ライブラリ モジュール
この記事ですでに説明した標準ライブラリ モジュールに加えて、subprocess、ConfigParser、readline、curses など、他にも便利な標準モジュールが多数あります。
次は何ですか?
この段階では、Python の使用経験に基づいて Linux の内部を探索してください。次のいずれかの方法を参照できます。 Linux の内部を調べるために多くのシェル スクリプト/コマンド パイプラインを作成する必要があった場合は、Python を試してみてください。多くのタスクを実行するユーティリティ スクリプトをより簡単に作成する方法が必要な場合は、Python を試してみてください。最後に、すでに Python を使用して Linux 上で他の目的でプログラムを作成している場合は、Python を使用して Linux の内部を探索してみてください。