python上でifconfigコマンドを実行し、返ってきた結果にIPアドレスがあればそれを表示することを考えます。
"LANG=C ifconfig"とするとコマンド結果が全て英語で返ってきて、処理しやすくなります。
import subprocess subprocess.call(("LANG=C", "ifconfig")) # エラー起きる
残念ながら、上記の方法だとエラーが発生します。"LANG=C"を使うときはcallではなくてPopenを使うと良いそうです。
Popenは公式によると、
17.5.1.2. Popen コンストラクター(原文) このモジュールの中で、根底のプロセス生成と管理は Popen クラスによって扱われます。簡易関数によってカバーされないあまり一般的でないケースを開発者が扱えるように、Popen クラスは多くの柔軟性を提供しています。 class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)
(中略)
注釈 子プロセスのために環境を変更する必要がある場合は、preexec_fn の中でそれをするのではなく env 引数を使用します。start_new_session 引数は、子プロセスの中で os.setsid() を呼ぶ過去の一般的な preexec_fn の使用方法の代わりになります。
(オプション引数多すぎ!)
結論から言うと、env引数で指定すれば良いです。LANG=Cは環境変更のコマンド(?)になるので、subprocess.callでifconfigと併用できなかったようです。
p = subprocess.Popen( "ifconfig", #stdin=subprocess.PIPE stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={'LANG':'C'}, shell=True ) out, err = p.communicate() print(out)
shell引数をTrueにしておかないと、"ifconfig"コマンドを認識してくれません。
stdout, stderr引数がないと、outとerrを受け取ることが出来ません。
結果としてoutは以下のようなものを得られます。
b'eth0 Link encap:Ethernet HWaddr b8:27:eb:xx:xx:xx \n UP BROADC AST MULTICAST MTU:1500 Metric:1\n RX packets:4431131 errors:0 dropped :9222 overruns:0 frame:0\n TX packets:18104015 errors:0 dropped:0 overr uns:0 carrier:0\n collisions:0 txqueuelen:1000 \n RX bytes:122 0313021 (1.1 GiB) TX bytes:3488088120 (3.2 GiB)\n\nlo Link encap:Local L oopback \n inet addr:127.0.0.1 Mask:255.0.0.0\n inet6 addr: ::1/128 Scope:Host\n UP LOOPBACK RUNNING MTU:65536 Metric:1\n RX packets:31487788 errors:0 dropped:0 overruns:0 frame:0\n TX packet s:31487788 errors:0 dropped:0 overruns:0 carrier:0\n collisions:0 txque uelen:1 \n RX bytes:29619310733 (27.5 GiB) TX bytes:29619310733 (27.5 GiB)\n\nwlan0 Link encap:Ethernet HWaddr b8:27:eb:xx:xx:xx \n ine t addr:192.168.5.129 Bcast:192.168.5.255 Mask:255.255.255.0\n inet6 a ddr: fe80::9e6e:73a1:2f3a:e0b1/64 Scope:Link\n UP BROADCAST RUNNING MUL TICAST MTU:1500 Metric:1\n RX packets:19745725 errors:0 dropped:30867 91 overruns:0 frame:0\n TX packets:1280736 errors:0 dropped:0 overruns: 0 carrier:0\n collisions:0 txqueuelen:1000 \n RX bytes:1023118 1 (9.7 MiB) TX bytes:1462394071 (1.3 GiB)\n\n'
結果はバイナリで返ってきていますので、適当にdecodeして文字列に直してから処理をします。
str_out = out.decode("ascii", "ignore") str_out_lines = str_out.splitlines() ip_addr = {"eth0":"", "wlan0":"", "lo":"", "":""} now_if = "" for line in str_out_lines: line = line.lower() if line.startswith("eth0"): now_if = "eth0" continue elif line.startswith("lo"): now_if = "lo" continue elif line.startswith("wlan0"): now_if = "wlan0" continue if "inet addr:" in line: blocks = line.split() # blocks[1] = "addr:xxx.xxx.xxx.xxx" ip_addr[now_if] = blocks[1][5:] # 確認のため標準出力する for key in ip_addr: print("ip_addr[{}] = {}".format(key, ip_addr[key]))
標準出力の結果は以下のようになります。
ip_addr[lo] = 127.0.0.1 ip_addr[] = ip_addr[eth0] = 192.168.5.128 ip_addr[wlan0] = 192.168.5.129