Pythonでシェルコマンドの実行結果をリストで渡す方法

More than 3 years have passed since last update.


はじめに

Pythonでシェルコマンドを扱いたい場合には、一般的にsubprocessモジュールを使う。モジュール内のstdout.readlines()を使うとリストとして結果を渡すことが可能であるが、実行するシェルコマンドが複数行に渡る場合、改行コード(ラインフィード)が一緒に渡ってしまう。そこで改行コード(ラインフィード)を取り除いた状態でリストを渡すには以下のように処理すればよい。

ここではシェルコマンドとして、ls -lをPythonから実行する例を使って解説する。

今回、以下の3通りに沿って3つスクリプトを作成した。


  • シェルの実行結果と同じものを取得する場合(res_cmd.py)

  • ラインフィードありのリストを取得する場合(res_cmd_lfeed.py)

  • ラインフィードなしのリストを取得する場合(res_cmd_no_lfeed.py)

実際に、ls -lを実行した場合の結果サンプルは以下の通りであるとする。

$ ls -l

total 12
-rwxr-xr-x 1 root root 260 Jun 16 18:48 res_cmd_lfeed.py
-rwxr-xr-x 1 root root 378 Jun 16 18:49 res_cmd_no_lfeed.py
-rwxr-xr-x 1 root root 247 Jun 16 18:48 res_cmd.py


シェルの実行結果と同じものを取得する場合

communicate()の1つ目の配列要素を取得すれば良い。


res_cmd.py

#!/usr/bin/python

import subprocess

def res_cmd(cmd):
return subprocess.Popen(
cmd, stdout=subprocess.PIPE,
shell=True).communicate()[0]

def main():
cmd = ("ls -l")
print(res_cmd(cmd))

if __name__ == '__main__':
main()


以下の通り、スクリプトの実行結果はls -lを実行した場合と同じである。

$ ./res_cmd.py

total 12
-rwxr-xr-x 1 root root 260 Jun 16 18:48 res_cmd_lfeed.py
-rwxr-xr-x 1 root root 378 Jun 16 18:49 res_cmd_no_lfeed.py
-rwxr-xr-x 1 root root 247 Jun 16 18:48 res_cmd.py


ラインフィードありのリストを取得する場合

stdout.readlines()を使う。


res_cmd_lfeed.py

#!/usr/bin/python

import subprocess

def res_cmd_lfeed(cmd):
return subprocess.Popen(
cmd, stdout=subprocess.PIPE,
shell=True).stdout.readlines()

def main():
cmd = ("ls -l")
print(res_cmd_lfeed(cmd))

if __name__ == '__main__':
main()


ラインフィードが含まれた結果のリストが取得できる。

$ ./res_cmd_lfeed.py

['total 12\n', '-rwxr-xr-x 1 root root 261 Jun 16 18:52 res_cmd_lfeed.py\n', '-rwxr-xr-x 1 root root 380 Jun 16 18:52 res_cmd_no_lfeed.py\n', '-rwxr-xr-x 1 root root 248 Jun 16 18:51 res_cmd.py\n']


ラインフィードなしのリストを取得する場合

stdout.readlines()を使い、かつ、リスト内包表記でrstrip("\n")を使う。


res_cmd_no_lfeed.py

#!/usr/bin/python

import subprocess

def res_cmd_lfeed(cmd):
return subprocess.Popen(
cmd, stdout=subprocess.PIPE,
shell=True).stdout.readlines()

def res_cmd_no_lfeed(cmd):
return [str(x).rstrip("\n") for x in res_cmd_lfeed(cmd)]

def main():
cmd = ("ls -l")
print(res_cmd_no_lfeed(cmd))

if __name__ == '__main__':
main()


ラインフィードを除いた結果のリストが取得できる。

$ ./res_cmd_no_lfeed.py

['total 12', '-rwxr-xr-x 1 root root 261 Jun 16 18:52 res_cmd_lfeed.py', '-rwxr-xr-x 1 root root 380 Jun 16 18:52 res_cmd_no_lfeed.py', '-rwxr-xr-x 1 root root 248 Jun 16 18:51 res_cmd.py']