리눅스 환경을 사용하고 계시다면, 쉘 명령어에 익숙하실 것입니다.
만약 파이썬을 활용하신다면, 자동화 시도를 해보셨을 가능성이 높습니다. 이는 시간을 절약하는 효과적인 방법이죠. 때로는 작업을 자동화하기 위해 bash 스크립트를 사용하기도 합니다.
파이썬은 bash보다 스크립트 작성에 더 편리하며, 파이썬 스크립트 관리는 bash 스크립트에 비해 더욱 용이합니다. 하지만 bash 스크립트가 복잡해질수록 유지보수가 어려워지는 것을 경험하셨을 겁니다.
그렇다면 이미 작성된 bash 스크립트를 파이썬으로 실행해야 하는 상황이라면 어떻게 해야 할까요?
파이썬에서 bash 명령어 및 스크립트를 실행할 수 있는 방법이 있을까요?
물론입니다. 파이썬에는 ‘subprocess’라는 내장 모듈이 있어 파이썬 스크립트 내에서 명령어와 스크립트를 실행할 수 있도록 도와줍니다. 지금부터 파이썬 스크립트에서 bash 명령어와 스크립트를 실행하는 방법을 자세히 알아보겠습니다.
Bash 명령어 실행
앞서 언급했듯이 ‘subprocess’ 모듈은 bash 명령어와 스크립트 실행에 사용되며, 다양한 함수와 클래스를 제공합니다.
이 모듈에서 핵심적으로 알아야 할 것은 ‘run’ 함수와 ‘Popen’ 클래스입니다. 이 두 가지 요소는 파이썬 스크립트에서 bash 명령을 실행하는 데 필수적입니다. 하나씩 자세히 살펴보겠습니다.
subprocess.run()
subprocess.run() 함수는 문자열 목록을 위치 인수로 받습니다. 이 목록은 bash 명령어와 해당 명령의 인수를 포함해야 합니다. 목록의 첫 번째 요소는 명령어 이름이며, 나머지는 명령에 대한 인수입니다.
간단한 예시를 보겠습니다.
import subprocess subprocess.run(["ls"])
위 스크립트는 스크립트가 실행되는 현재 작업 디렉터리의 모든 항목을 출력합니다. 이 스크립트는 명령어에 대한 추가 인수를 포함하지 않고 단순히 ‘ls’ 명령어만 실행합니다. ‘ls’ 명령어에 ‘-l’, ‘-a’, ‘-la’와 같은 다양한 인수를 추가할 수 있습니다.
명령어 인수를 포함한 간단한 예시를 보겠습니다.
import subprocess subprocess.run(["ls", "-la"])
위 명령어는 숨김 파일을 포함한 모든 파일을 권한 정보와 함께 표시합니다. 여기서 ‘la’는 파일 및 디렉터리 추가 정보와 숨김 파일을 표시하는 인수입니다.
명령어를 작성하는 과정에서 실수가 발생할 수 있습니다. 이러한 오류를 캡처하여 나중에 사용하려면 어떻게 해야 할까요? ‘stderr’라는 키워드 인수를 활용하면 됩니다.
다음 예시를 참고하세요.
import subprocess result = subprocess.run(["cat", "sample.txt"], stderr=subprocess.PIPE, text=True) print(result.stderr)
이 예시를 실행하기 전에 작업 디렉터리에 ‘sample.txt’라는 파일이 없는지 확인하세요. ‘stderr’ 키워드 인수에 ‘PIPE’ 값을 할당하면 오류 메시지를 객체 형태로 반환받을 수 있습니다. 해당 오류 메시지는 나중에 동일한 이름으로 접근할 수 있습니다. 또한 ‘text’ 키워드 인수는 출력 형식이 문자열임을 명시하는 역할을 합니다.
마찬가지로, ‘stdout’ 키워드 인수를 사용하면 명령어의 출력을 캡처할 수 있습니다.
import subprocess result = subprocess.run(["echo", "Hello, World!"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) print(result.stdout)
subprocess.run() – 입력
‘input’ 키워드 인수를 사용하여 명령어에 입력을 제공할 수 있습니다. 입력 값은 문자열 형식으로 전달해야 하므로, ‘text’ 키워드 인수를 ‘True’로 설정해야 합니다. 기본적으로는 바이트 단위로 입력값을 처리합니다.
다음 예시를 살펴보겠습니다.
import subprocess subprocess.run(["python3", "add.py"], text=True, input="2 3")
위 프로그램에서 ‘add.py’라는 파이썬 스크립트는 두 개의 숫자를 입력으로 받습니다. ‘input’ 키워드 인수를 사용하여 파이썬 스크립트에 입력값을 전달합니다.
subprocess.Popen()
subprocess.Popen() 클래스는 subprocess.run() 함수보다 더 많은 기능을 제공합니다. 명령어를 실행할 때 더 많은 옵션을 제공하며, Popen 클래스의 인스턴스를 생성하여 명령어 실행 상태를 확인하거나 출력을 가져오거나 입력을 제공하는 등 다양한 작업을 수행할 수 있습니다.
subprocess.Popen() 클래스에는 여러 가지 메소드가 존재하며, 예제 코드와 함께 하나씩 살펴보겠습니다.
wait()
wait() 메소드는 명령어가 완료될 때까지 기다리는 데 사용됩니다. 파이썬 스크립트의 다음 코드는 wait() 메소드 뒤에 오는 이전 명령어가 완료될 때까지 실행이 중단됩니다. 예시를 보겠습니다.
import subprocess process = subprocess.Popen(["ls", "-la"]) print("Completed!")
위 코드를 실행하고 결과를 확인하면 “Completed!” 메시지가 명령 실행 전에 출력되는 것을 확인할 수 있습니다. 이를 wait() 메소드를 사용해 해결할 수 있습니다. 명령어가 완료될 때까지 기다려보겠습니다.
import subprocess process = subprocess.Popen(["ls", "-la"]) process.wait() print("Completed!")
위 코드의 출력 결과를 보면 wait() 메소드가 정상적으로 작동하는 것을 확인할 수 있습니다. print문은 명령 실행이 완료된 후에 실행됩니다.
communicate()
communicate() 메소드는 명령어의 출력, 오류를 가져오고 명령어에 입력을 제공하는 데 사용됩니다. 이 메소드는 출력과 오류를 각각 포함하는 튜플을 반환합니다. 예시를 보겠습니다.
import subprocess process = subprocess.Popen(["echo", "Hello, World!"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) result = process.communicate() print(result)
subprocess.Popen() – 입력
Popen 클래스에 직접 입력값을 전달할 수는 없습니다. 명령어에 입력을 제공하려면 ‘stdin’이라는 키워드 인수를 사용해야 합니다. Popen 클래스의 인스턴스는 ‘stdin’ 객체를 제공하며, 여기에 ‘write()’ 메소드를 사용하여 명령에 입력을 제공할 수 있습니다.
앞서 언급했듯이 입력은 기본적으로 바이트열 객체로 처리되므로, Popen 인스턴스를 생성할 때 ‘text’ 키워드 인수를 ‘True’로 설정하는 것을 잊지 마세요.
다음 예시를 참고하세요.
import subprocess process = subprocess.Popen(["python3", "add.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) process.stdin.write("2 3") process.stdin.close() print(process.stdout.read())
poll()
poll() 메소드는 명령어 실행이 완료되었는지 여부를 확인하는 데 사용됩니다. 명령어가 여전히 실행 중인 경우, 이 메소드는 ‘None’을 반환합니다. 예시를 보겠습니다.
import subprocess process = subprocess.Popen(['ping', '-c 5', 'geekflare.com'], stdout=subprocess.PIPE, text=True) while True: output = process.stdout.readline() if output: print(output.strip()) result = process.poll() if result is not None: break
위 코드에서는 5개의 요청과 함께 ‘ping’ 명령어를 사용했습니다. 명령어 실행이 완료될 때까지 무한 루프를 실행합니다. poll() 메소드를 사용하여 명령어 실행 상태를 확인하고, poll() 메소드가 ‘None’ 이외의 코드를 반환하면 실행이 완료된 것으로 간주하고 루프를 종료합니다.
Bash 스크립트 실행
이제까지는 명령어를 실행하는 두 가지 방법을 살펴보았습니다. 이제 파이썬 스크립트에서 bash 스크립트를 실행하는 방법을 알아보겠습니다.
‘subprocess’ 모듈에는 ‘call()’ 이라는 함수가 있으며, 이 함수는 bash 스크립트를 실행하는 데 사용됩니다. 이 함수는 bash 스크립트의 종료 코드를 반환합니다. 일반적으로 bash 스크립트의 기본 종료 코드는 ‘0’입니다. 예시를 살펴보겠습니다.
다음과 같이 ‘practice.sh’라는 bash 스크립트를 생성합니다.
#!/bin/bash echo "Hello, World!" exit 1
이제 위 bash 스크립트를 실행하는 파이썬 스크립트를 작성합니다.
import subprocess exit_code = subprocess.call('./practice.sh') print(exit_code)
위 파이썬 스크립트를 실행하면 다음과 같은 결과를 얻을 수 있습니다.
Hello, World! 1
결론
파이썬에서 bash 명령어와 스크립트를 실행하는 방법을 알아보았습니다. 이를 활용하여 작업을 더욱 효율적으로 자동화할 수 있습니다.
즐거운 코딩하세요! 👨💻