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",
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()
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
eth0が有線LAN、wlan0が無線LANのIPアドレスです。