質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3939閲覧

Python3 subprocess関数のshellオプションについて

person

総合スコア224

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2021/05/02 04:04

編集2021/05/02 04:37

例えば、Windowsで

Python

1import subprocess as sp 2 3cmd = "dir" # Linuxの場合は "ls" 4ret = sp.run(cmd, stdout=sp.PIPE, shell=True) 5 6print(ret.stdout.decode("cp932")) # Linuxの場合は "utf-8" または 指定なし

を実行すると

ドライブ C のボリューム ラベルは Windows です ボリューム シリアル番号は A0A0-0123 です C:\Users\user01 のディレクトリ 2021/04/15 (木) 21:13 <DIR> . 2021/04/15 (木) 21:13 <DIR> .. 2020/07/22 (水) 20:28 <DIR> .vscode 2020/11/12 (木) 14:40 <DIR> 3D Objects 2021/03/31 (水) 09:03 <DIR> ansel 2020/08/10 (月) 00:33 <DIR> Apple 2020/11/12 (木) 14:40 <DIR> Contacts 2021/05/02 (日) 12:46 <DIR> Desktop 2020/11/20 (金) 00:03 <DIR> Documents 2020/11/12 (木) 14:40 <DIR> Downloads 2021/01/17 (日) 00:25 <DIR> Favorites 2020/11/12 (木) 14:40 <DIR> Links 2020/11/12 (木) 14:40 <DIR> Music 2021/04/24 (土) 14:09 <DIR> OneDrive 2021/02/04 (木) 09:24 <DIR> Pictures 2020/11/12 (木) 14:40 <DIR> Saved Games 2020/11/12 (木) 14:40 <DIR> Searches 2021/03/31 (水) 14:34 <DIR> share 2021/05/02 (日) 12:44 <DIR> Videos 0 個のファイル 0 バイト 19 個のディレクトリ 306,688,061,440 バイトの空き領域

と出てきます。

shellを指定しない(shell=Falseである)場合、

Traceback (most recent call last): File "c:/Users/user01/Desktop/test.py", line 4, in <module> ret = sp.run(cmd, stdout=sp.PIPE) File "C:\Users\user01\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 489, in run with Popen(*popenargs, **kwargs) as process: File "C:\Users\user01\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 854, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "C:\Users\user01\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 1307, in _execute_child hp, ht, pid, tid = _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。

と出てきます。

Linuxだとコマンド文をスペース区切りのリストで引数に指定してあげればいいようです。
例えば、"ls -a" というコマンドを実行するときは、

import subprocess as sp ret = sp.run(["ls", "-a"], stdout=sp.PIPE)

となります。

shell=Falseを指定した場合のメリットってありますか?
普通に使う分にはshell=Trueにすればいいような気がしたのですが、shell=Falseとして実際に使う場面が想像できなかったので。

追記

ドキュメントには下記のように書かれてました。

subprocess --- サブプロセス管理¶

args はすべての呼び出しに必要で、文字列あるいはプログラム引数のシーケンスでなければなりません。一般に、引数のシーケンスを渡す方が望ましいです。なぜなら、モジュールが必要な引数のエスケープやクオート (例えばファイル名中のスペースを許すこと) の面倒を見ることができるためです。単一の文字列を渡す場合、shell は True でなければなりません (以下を参照)。もしくは、その文字列は引数を指定せずに実行される単なるプログラムの名前でなければなりません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ざっくり言うと、引数を個別に指定したい場合。

例1:
引数がもともとリストである場合。

Python

1filelist = glob.glob("*.txt") 2 3.run(["/bin/cat", "-n", *filelist])

例2:
特に、引数の中にシェルの特殊文字(空白とか、引用符とか、ワイルドカードなど)が含まれていると、シェル経由だと適切に引数のクォート処理をしないといけないので、面倒。

Python

1.run(["/bin/xxx", "-a", "aa bb cc", "*"]) 23.run("/bin/xxx -a 'aa bb cc' '*'", shell=True)

例3:
外部から得られた値をコマンドラインの一部に使う場合は、適切に前処理しておかないと脆弱性になる。
シェル経由でない場合もファイル名などになる場合は、前処理が不要というわけでは無いが、
~~;/bin/rm -rf $HOME/*みたいな心配はしなくて良い。

投稿2021/05/02 04:30

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

person

2021/05/02 04:46

回答ありがとうございます。 例1の、もともとリストで取得していてそれを指定する場合が想像できなかったのですが、取得の仕方によってはリストで取得することもあるんですね。 例2については、glob()やlsコマンド等で取得したパスを変数に入れてそのままcall()やrun()などに渡すことだけを想定していたので、そのまま指定すればいいかなって思っていましたが、ソースコード上にじかにパスを書く場合などはその必要があるんですね。(確かにターミナルでlsコマンド打ったときにエスケープ文字がありました。) 例3については、自分にはシェルの知識がないのであとで調べてみます。
otn

2021/05/02 05:03

> 例2については、glob()やlsコマンド等で取得したパスを変数に入れてそのままcall()やrun()などに渡すことだけを想定していたので、そのまま指定すればいいかなって思っていましたが、ソースコード上にじかにパスを書く場合などはその必要があるんですね。 いいえ。ソースコードに直に書く場合は、最初からクォートしたものを書けばいいので簡単です。 プログラムで取得したファイル名を、shell=Trueのコマンドラインに渡すのは、ファイル名に(ワイルドカード文字や引用符などが含まれているケースは対応しないとしても)、空白が含まれている場合は時々あるので(Windowsだと頻繁に)、ファイル名はそのまま使えず、加工が必要です。 Linuxの ls なら、ls -q というオプションで特殊文字をクォートした上で出力してくれるので、それを使えば良いのですが。
guest

0

shell=Trueの場合、セキュリティについて気をつける必要がでてくるということです。
https://docs.python.org/ja/3/library/subprocess.html#security-considerations

使い捨てや利用者が自分くらいであればshell=Trueの方が便利でいいと思いますが、
パッケージソフトやWebサービスのような第三者が使うソフトを作る場合は、

  1. subprocessをそもそも使わない
  2. 使ってもshell=Falseにする
  3. やむおえずshell=True

こんな葛藤はありそうです。

投稿2021/05/02 04:39

hide5stm

総合スコア426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

person

2021/05/02 04:54

回答ありがとうございます。 > shell=Trueの場合、セキュリティについて気をつける必要がでてくるということです。 外部へ公開するようなものは、shell=Trueを使わないようにコーディングする必要が出てくるんですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問