문제 세팅을 위해 로컬 스트레스를 돌리는 경우가 왕왕 있습니다. 이럴 때 파이썬 스크립트를 자주 사용하는 편입니다. 스트레스를 돌릴 때, diff 함수를 상당히 자주 사용합니다. 수만개의 스트레스를 자동으로 돌리는 방법이 없을까요? 이 글에서는 subprocess run 함수로 이러한 일을 하는 방법을 알아봅니다.
명령어 결과 얻어오기
test/diff 디렉토리에 1.in, 2.in, 3.in 이렇게 3개의 파일이 있습니다.
1.in과 2.in에는 1이, 3.in에는 3이 있습니다. diff는 몇 개의 파일을 비교하는데요. 두 개의 파일을 비교할 때 리턴값은 아래와 같습니다.
- 두 파일이 같으면 0
- 두 파일이 다르면 1
- 에러가 발생하면 2
실행을 시켜 보겠습니다.
diff 1.in 2.in 명령어를 실행시켰습니다. 그리고 echo $?를 실행시켰습니다. 여기서, $?는 이전에 실행한 명령어의 리턴값을 가져옵니다. diff는 두 파일이 같으면 0을 리턴합니다. 1.in과 2.in은 같은 내용이 있었기 때문에, 0을 돌려줍니다.
반대로, 1.in과 3.in을 비교해 봅시다. 1.in에는 1이 있지만 3.in에는 3이 있습니다. 둘이 다릅니다. 따라서, 1이 리턴되게 됩니다. 두 솔루션을 비교할 때, 결과 파일 2개를 diff의 리턴값으로 비교하면 된다는 것을 알 수 있습니다. local stress 어렵지 않게 구축 가능합니다.
파이썬 subprocess run 함수의 returncode 알아보기
이제, 문제의 함수를 보도록 합시다.
엄청나게 많은 인자들이 있습니다. 이 글에서 언급하는 keyword는 2개입니다.
- args
- stdout
args는 명령어를 의미합니다. 예를 들어, ls -l의 경우 [“ls”, “-l”]을 넘겨주면 됩니다. 맨 밑에 보시면, 인자로 넘겨준 args를 가지고 command를 돌립니다. 그리고, CompletedProcess 인스턴스를 돌려준다고 되어 있어요.
이 CompletedProcess 인스턴스에는 returncode가 있습니다. 명령어를 실행한 후의 exitcode 입니다. 이것이 핵심입니다. diff로 두 파일을 비교하는 명령어를 실행시켰다면 어떤 값이 저장될까요?
- 두 파일이 같다면 0
- 두 파일이 다르다면 1
- 에러가 발생하면 2
이제, 예제를 보도록 하겠습니다.
먼저 1번 예제입니다. run의 args로 [“diff”, “1.in”, “2.in”]을 넘겨주었습니다. 이는 “diff 1.in 2.in” 명령어를 실행한다는 의미입니다. 이 명령어의 exitCode를 받는데, 같기 때문에 0을 받습니다. 다음, 2번째 run은 “diff 1.in 3.in”을 실행합니다. 1.in과 3.in은 다르기 때문에 1이 리턴됩니다. 결과를 볼까요?
0과 1이 나옵니다. 그런데, 중간에 출력이 들어갑니다. 이는, diff 명령어가 두 파일이 다르면 stdout에 출력해 버리기 때문입니다.
여기서 핵심은 파이썬 subprocess run 함수가 CompletedProcess 인스턴스를 리턴합니다. 이 리턴값의 returncode를 가져오면 명령어의 리턴값을 얻어올 수 있게 됩니다.
diff 출력 제외하기
run 함수를 실행시킬 때, diff 함수의 출력을 제외하려면 어떻게 해야 할까요? 간단합니다. stdout을 표준 출력으로 하는 것이 아니라, 다른 파일로 해 버리면 됩니다. subprocess.DEVNULL은 아무 파일에도 출력하지 않고 버립니다.
예제 2번 프로그램을 보겠습니다. 2번째 run 함수의 stdout에 subprocess.DEVNULL을 넘겨주었습니다. 이는, 명령어를 실행시키는 프로세스의 표준 출력을 DEVNULL로 덮어쓴다는 의미입니다.
실행 결과는 위와 같습니다. 예제 1과는 다르게 다른 부분이 출력되지 않았습니다. 이는, 자식 프로세스인 diff의 output이 /dev/null로 출력했기 때문입니다. output 캡쳐하는 부분은 다음 글에 자세히 알아보도록 하겠습니다.