아르바이트 중 이런 업무를 할당 받았다.
(su - {username})
(conda activate {envs})
업무를 수행하기 위해서는 반드시 os에서 권한, 환경, 디렉토리를 넘나들며 파이썬 스크립트, 리눅스 커맨드를 실행해야 했다. 이런 업무를 수행할 수 있게 해주는 2가지 모듈이 있는데 subprocess와 pexpect였다. 이 두가지에 대해서 살펴보자
새로운 프로세스를 만들어준다. 이 프로세스에 I/O/Error에 대한 파이프를 연결할 수 있다. subprocess는 python의 os.system, os.spawn*
모듈들을 대체한다.
일회성 프로세스를 생성할 때는 run()
메소드를 사용하자 python 3.5 이상부터 사용이 가능하고 조금 더 강력한 기능을 원한다면 Popen()을 사용하자
import subprocess
subprocess.run(['dir'], shell=True)
window 기준 해당 디렉토리에 존재하는 파일 리스트를 리턴한다. linux에서는 첫번째 args에 리스트 형태를 넘겨줄 때는 shell=False
로 지정하는데 window에서는 항상 True로 지정해야한다... 이상하네 문서를 읽다보니 dir, copy 같은 녀석들을 커맨드를 사용할 때는 shell=True로 설정하고 배치나 exe를 실행할 때는 shell=True가 필요 없다고 한다. 사용할 때는 어쨌든 리스트로 넘기는 이유는 shell injection 공격을 방지하기 위해서이다. 당연히 리스트 없이 그냥 커맨드를 넘겨도 된다.
['dir'] = 'dir' 이라는 뜻이다.
linux의 경우엔['ls'] 로 넘길 때는 shell=Fasle,'ls'로 넘길 때는 shell=True로 지정해야한다. 어쨌든 run() 메소드는 CompletedProcess
인스턴스를 리턴한다. 이녀석은 args, returncode, stdout, stderr, check_returncode()
로 이루어져있다.
여러 동작을 할 수도 있다. subprocess.run(['dir', 'findstr', 'workspace'], shell=True)
list의 원소는 command 기준 스페이스바의 공백과 파이프가 기준인 듯 하다.
['dir', 'findstr', 'workspace'] = dir | findstr workspace
Popen()은 run()보다 강력하다고 한다. 공식 문서의 매개변수들만 봐도 조금 더 많은 매개변수를 받을 수 있다. 기본적으로 사용하는 방식은 비슷하지만 communicate()
를 통해 Popen()을 통해 생성한 프로세스의 동작이 끝날 때 까지 기다렸다가 stderr, stdout을 받아 올 수 있다.
또한 stdin을 사용하여 input을 받고 파일을 입력할 수도 있다. stdin을 사용할 때는 꼭 flush()를 사용해야한다.
pexpect는 ssh, ftp, mencoder, passwd 같은 녀석들과 상호작용하기 용이하게 디자인 되었다. 예시 코드를 살펴보자
import pexpect
child = pexpect.spawn('ftp ftp.openbsd.org')
child.expect('Name .*: ')
child.sendline('anonymous')
child.expect('Password:')
child.sendline('noah@example.com')
child.expect('ftp> ')
child.sendline('lcd /tmp')
child.expect('ftp> ')
child.sendline('cd pub/OpenBSD')
child.expect('ftp> ')
child.sendline('get README')
child.expect('ftp> ')
child.sendline('bye')
위의 코드는 두 개의 메인 메소드로 이루어진다.
expect()
: 자식 어플리케이션이 string을 리턴하는 것을 기다린다. 문자열을 정규식으로 표현하여 복잡한 패턴들도 매치시킬 수 있다. expect()
는 before 과 after 속성을 가진 자식 어플리케이션을 리턴한다. before은 기대되는(expected) 문자열 패턴을 포함하고 after는 기대된 패턴(expected pattern)에 의하여 매치가 된 문자열들로 이루어져있다.send()
: 자식 어플리케이션의 terminal에 매개변수에 입력된 string을 전송한다. Popen()
과 같이 프로세스를 생성하는 메소드는 spawn()
이다.
대부분 ssh 접속을 자동화할 때 사용하는 듯 하다..
불곰님 블로그 설명을 너무 잘해주셨다.