엄범


Note )

subprocess로 실행하는 바이너리가 출력→입력대기 순서로 진행할 때,

``c read() -> write()``를 주었는데도 제대로 동작하지 않는 경우가 있다.

이는 실행하는 바이너리 자체에서 입력 대기 하기 전에 출력을 파이썬으로 보내주어야 하는데, 입력 대기가 끝난 이후에 파이썬으로 출력 내용을 보내기 때문에 발생하는 현상으로 보인다. 그래서, 파이썬 단에서는 파이프를 새로 만들든 무슨 짓을 하든 해결이 안되고, 바이너리에서 flush해주는 수 밖에 없는 듯.


Popen

세부적인 제어는 `` subprocess.Popen()``을 사용해야 한다.

stdio 연결

```python
>>> p = subprocess.Popen(argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env={"ENV_":"value"})
>>> p
<subprocess.Popen object at 0x7feb23e9a210>
>>> p.stdin.write("\x00\x0a\x00\xff")
>>> p.communicate("stdin input string")
("stdout output!", None)   #[0] == stdout, [1] == stderr
```
단점은 `` stderr``이 `` rb``로 열려서 여기에 쓸 수가 없다. 이미 열려있는 파일의 access mode를 변경하는건 OS 단에서 이미 안되기 때문에 따로 파이프를 생성해 지정해주어야 한다. File object, File descriptor 둘 다 지정 가능하다.
Note ) 사실 그냥 파이프를 따로 생성해서 지정해주는게 더 직관적으로 동작하는 것 같은데, 이렇게 따로 지정하는 경우 그 파이프 변수로 접근해야만 한다. `` p.stdin``이 설정되는 경우는 `` subprocess.PIPE``를 지정하는 경우 말고는 없기 때문에 `` p.stdin`` 따위로 접근하면 ``python None``을 반환한다. 
파이프 한 개(r, w 한 쌍) 당 한 쪽 방향으로만 사용할 수 있다는 점 유의.  [IPC] pipe
즉, 두 프로세스를 양방향으로 각자 r,w할 수 있도록 연결하려면 파이프가 두 개 필요.

cat 예제

  • `` Popen("cat")``일 때 stdin 지정 안하면 interactive에서는 stdin이 겹쳐서 입력이 잘 안된다.
  • ``python stdout=subprocess.PIPE`` 적고 `` p.stdout.read()``하면 왜인지 안된다.
```python
>>> r, w = os.pipe()
>>> p = subprocess.Popen("cat", stdin=subprocess.PIPE, stdout=w)
>>> p.stdin.write("1234")
>>> os.read(r, 4)
'1234'
```
```python
>>> stdin_r, stdin_w = os.pipe()
>>> stdout_r, stdout_w = os.pipe()
>>> p = subprocess.Popen("cat", stdin=stdin_r, stdout=stdout_w)
>>> os.write(stdin_w, "1234")
4
>>> os.read(stdout_r, 4)
'1234'
```

간단하게 사용할 때

```python

import subprocess


subprocess.run(['ls', '-al'], shell=True)

```

* `` WindowsError: [Error 2] The system cannot find the file specified``가 발생하는 경우, Windows에서 `` .exe``말고 다른 확장자는 파일 이름만 적어 실행하는 것이 안되기 때문이다. 확장자까지 입력해주어야 한다.


리턴값을 이용하고 싶은 경우

```python

>>> import subprocess

>>> result = subprocess.run(["ls"], stdout=subprocess.PIPE)

>>> result

CompletedProcess(args=['ls'], returncode=0, stdout=b'__init__.py\n__pycache__\nclean.p

y\ncopy.py\nlog.py\nrun.py\ntest.log\n')


# 3.7.0부터는 capture_ouput을 사용하는게 좋음.
if (sys.version_info >= (3, 7, 0)):
    result = subprocess.run(args, capture_output=True, **kwargs)

# 이건 예전 버전이라 사용하지 않는 것이 좋다.

# result = subprocess.check_output(["ls"])

```


구식 OS

구식 OS에서는 `` subprocess`` 모듈이 없어 `` os`` 모듈을 사용해야한다.

```python

import os


os.system ('ls -al | grep "user")

os.popen("command")

```


'Languages & Frameworks > Python' 카테고리의 다른 글

[python] plotly  (0) 2017.07.19
[python] graph visualization  (0) 2017.07.19
[python] subprocess, Popen  (1) 2017.07.03
[python] assert / with / try-except  (0) 2017.07.02
[python] directory parse / glob / pathlib  (0) 2017.07.02
[python] 람다(lambda), fileter / map  (2) 2017.07.02