Python – Subprocess #2

구 버전의 함수를 대체하기

쉘의 백쿼트를 대체하기


output=`mycmd myarg`
# 위 명령을
output = check_output(["mycmd", "myarg"])

쉘 파이프라인


### shell
output=`dmesg | grep hda`
### python
p1 = Popen(['dmesg'], stdout=PIPE)
p2 = Popen(['grep', 'hda'], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close() ## p1이 SIGPIPE를 받는다. 
output = p2.communicate()[0]

혹은 쉘을 이용하면 파이프라인을 쉘에서 만들 수 있다.

output = check_output('dmesg | grep hda', shell=True)

os.s-y-s-t-e-m()을 대체


### old school
sts = os.s-y-s-t-e-m('mycmd' + ' myarg')
### new
sts = call('mycmd' + ' myarg', shell=True)

보다 실질적인 구현


try:
    retcode = call('mycmd' + ' myarg', shell=True)
    if retcode < 0:
        print("Child was terminated by signal", -retcode, file=sys.stderr)
    else:
        print("Child returned", retcode, file=sys.stderr)
except OSError as e:
    print("Execution failed:", e, file=sys.stderr)

os.spawn 대체


# pid = os.spawnlp(os.P_NOWAIT, '/bin/mycmd', 'mycmd', 'myarg')
# --> 
pid = Popen(["/bin/mycmd", "myarg"]).pis

# retcode = os.spawnlp(os.P_WAIT, '/bin/mycmd', 'mycmd', 'myarg')
# --> 
recode = call(['/bin/mycmd', 'myarg'])

# os.spawnvp(os.P_NOWAIT, path, args)
# --> 
Popen([path] + args[1:])

# os.spawnlpe(os.P_NOWAIT, '/bin/mycmd',' mycmd', 'myarg', env)
# -->
Popen(['/bin/mycmd', 'myarg'], env={"PATH": "/usr/bin"})

os.popen*() 류 대체

# (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
# -->
p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = p.stdin, p.stdout

# (child_stdin, chid_stdout, child_stderr) = \
#   os.popen3(cmd, mode, bufsize)
# --> 
p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
child_stdin, child_stdout, child_stderr = p.stdin, p.stdout, p.stderr)

# child_stdin, child_stdout_and_stderr = os.popen4(cmd, mode, bufsize)
# --> 
p = Popen(cmd, shell=True, bufsize=bufsize, 
            stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
child_stdin, child_stdout_and_stderr = p.stdin, p.stdout

리턴 코드 핸들링은 다음과 같이

# pipe = os.popen(cmd, 'w')
# ...
# rc = pipe.close()
# if rc is not None and rc >> 8:
    print("There was some errors")
# -->
process = Popen(cmd, 'w', stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
    print("There were some errors")

popen2 모듈의 함수들을 대체

# (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
# ==>;
p = Popen("somestring", shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)

# (child_stdout, child_stdin) = (p.stdout, p.stdin)
# (child_stdout, child_stdin) = \
# popen2.popen2(["mycmd", "myarg"], bufsize, mode)
# ==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

레거시 쉘 호출 함수들

파이썬 2.X대의 command 모듈은 아래 두 함수로 대체한다.


>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
>>> subprocess.getstatusoutput('cat /bin/junk')
(256, 'cat: /bin/junk: No such file or directory')

>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'