LoginSignup
0
0

PythonでWindowsのコマンドを実行したときの言語環境について

Posted at

Windows環境のPythonにおいてsubprocessを実行するとコマンドを実行できる
しかし, 次の問題が発生する

  1. PCの設定によって文字エンコーディングが変わること
  2. PCの言語環境によって返ってくる言葉が変わること

以上のことに対処した

先に結論

  1. 現在の文字エンコーディングは locale.getpreferredencoding() でわかる
  2. 言語環境は subprocess.run(['chcp.com', '437']) で変更できる

文字エンコーディングの対処

Pythonのsubprocessを使って入手できる出力はデコードする必要がある

subprocess.run(
    ['ipconfig'], check=True, stdout=subprocess.PIPE,).stdout

"""
\r\nWindows IP \x8d\\\x90\xac\r\n\r\n\r\n\x83C\x81[\x83T\x83l\x83b\x83g...
"""

日本語の環境では cp932 (shift-JIS) でデコードすればよい

subprocess.run(
    ['ipconfig'], check=True, stdout=subprocess.PIPE,)\
        .stdout.decode('cp932')

"""
\r\nWindows IP 構成\r\n\r\n\r\nイーサネット アダプター イーサネット:...
"""

しかし, 文字コードは言語環境が変われば変わってしまうため, ハードコーディングはしたくない

調べてるとchcpを使ってコードページを変更する例がでてくる
しかし、Pythonのsubprocessからは文字コードを変えることはできなかった。

subprocess.run(
    ['chcp.com', '65001'], check=True, stdout=subprocess.PIPE,).stdout

"""
Active code page: 65001\r\n
"""

subprocess.run(
    ['ipconfig'], check=True, stdout=subprocess.PIPE,).stdout

"""
\r\nWindows IP Configuration\r\n\r\n\r\nEthernet adapter \x83C\x81[\x83T\x83l\x83b\x83g: ...
"""

文字コードの確定

locale モジュールの getpreferredencoding 関数を用いることで環境の文字コードを取得可能である

locale.getpreferredencoding()

"""cp932"""

subprocess.run(
    ['ipconfig'], check=True, stdout=subprocess.PIPE,).stdout.decode(
        locale.getpreferredencoding())

"""
\r\nWindows IP 構成\r\n\r\n\r\nイーサネット アダプター イーサネット:...
"""

言語環境の設定

言語環境によって表示されるキーワードが変わる.
これは特定の情報を入手したいときにキー名が環境で代わり不便である.

p = subprocess.run(
    ['ipconfig'], check=True, stdout=subprocess.PIPE,)
data = p.stdout.decode(locale.getpreferredencoding()).split('\r\n')

for line in data:
    print(line)

"""
Japanese環境
----------
Windows IP 構成


イーサネット アダプター イーサネット:

   メディアの状態. . . . . . . . . . . .: メディアは接続されていません
   接続固有の DNS サフィックス . . . . .: 
...

US環境
----------
Windows IP Configuration


Ethernet adapter イーサネット:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : 
...
"""

そこで chcp コマンドによって言語環境を変更しUS環境で情報を取得する
(ただし上のように「Ethernet adapter イーサネット:」のような日本語文字が残ってしまうようだ)
https://learn.microsoft.com/ja-jp/windows-server/administration/windows-commands/chcp

コンテキストマネージャを使いこのように書ける


@contextmanager
def code_page(code_page: int):
    encoding = locale.getpreferredencoding()

    try:
        p = subprocess.run(
            ['chcp.com'], check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        init_cp = p.stdout.decode(encoding=encoding).replace('\r\n', '')\
            .split(' ')[-1]

        subprocess.run(
            ['chcp.com', str(code_page)], check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        yield
    finally:
        subprocess.run(
            ['chcp.com', init_cp], check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)

with code_page(437):
    d = subprocess.run(
        ['ipconfig'], check=True, stdout=subprocess.PIPE,)
data = d.stdout.decode(locale.getpreferredencoding()).split('\r\n')

with 文を使いコードページを臨時で変更することができる。

おわり

コード全体


from contextlib import contextmanager
import subprocess
import locale

# %%
@contextmanager
def code_page(code_page: int):
    encoding = locale.getpreferredencoding()

    try:
        p = subprocess.run(
            ['chcp.com'], check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        init_cp = p.stdout.decode(encoding=encoding).replace('\r\n', '')\
            .split(' ')[-1]

        subprocess.run(
            ['chcp.com', str(code_page)], check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        yield
    finally:
        subprocess.run(
            ['chcp.com', init_cp], check=True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# %%
def get_ipconfig():
    with code_page(437):
        d = subprocess.run(
            ['ipconfig'], check=True, stdout=subprocess.PIPE,)
    return d.stdout.decode(locale.getpreferredencoding()).split('\r\n')

# %%
data = get_ipconfig()
for line in data:
    print(line)

# %%

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0