시스템 상호작용
시스템 상호작용 (system)
Raku 프로그램이 운영체제와 주고받는 일은 생각보다 자주 생겨요. 명령줄 인자를 읽고, 환경 변수를 확인하고, 외부 프로그램을 실행하고, 심지어 네이티브 시스템 함수를 직접 부를 때도 있죠. 이 페이지에서는 그런 시스템 상호작용을 Raku에서 어떻게 다루는지 한 번에 훑어봅니다.
명령줄 인자 받아오기
가장 간단한 방법은 @*ARGS 변수입니다. 프로그램 이름 뒤에 나오는 문자열들이 이 배열에 담겨요. 환경 변수는 %*ENV에 들어 있는데요, 예를 들어 셸에서 이렇게 설정했다면
export API_KEY=1967196417966160761fabc1511067
./consume_api.raku
프로그램 안에서 이렇게 꺼내 쓸 수 있어요.
my $api-key = %*ENV<API_KEY> // die "Need the API key";
만약 환경 변수 API_KEY가 미리 정의되어 있지 않다면 이 코드는 실패해요. 존재하지 않는 키를 die로 막아두는 거죠.
명령줄 인자가 파일 이름을 나타낸다면 Raku는 더 편한 도구를 제공해요. 바로 $*ARGFILES 동적 변수입니다. 여러 파일을 하나처럼 순회할 수 있어요.
for $*ARGFILES.lines -> $l {
say "Long lines in {$*ARGFILES.path}"
if $l.chars > 72 ;
}
이 프로그램을 argfiles.raku *.raku처럼 실행하면, 72자를 넘는 줄을 찾을 때마다 해당 파일 이름을 출력해요. $*ARGFILES는 명령줄에 나열된 모든 파일의 파일핸들을 품고 있고, .lines가 각 파일에서 한 줄씩 차례로 읽을 때마다 $*ARGFILES.path가 현재 처리 중인 파일로 바뀝니다. 파일 묶음을 다루는 스크립트에서는 그야말로 편리한 API예요.
대화형으로 입력 받기
prompt를 쓰면 실행 중인 프로그램이 사용자에게 데이터를 물을 수 있어요.
my UInt $num-iters = prompt "How many iterations to run: ";
실행하면 메시지를 띄우고 사용자가 입력한 값을 돌려줍니다.
동기·비동기로 외부 프로그램 실행하기
외부 프로그램을 실행하는 루틴은 두 가지가 있어요. run과 shell입니다. 둘 다 IO 역할에 존재해서, IO::Path처럼 그 역할을 섞은 모든 클래스에서 쓸 수 있어요. 둘 다 Proc 객체를 돌려주지만, 핵심 차이는 run은 가능하면 시스템 셸을 거치지 않으려는 반면 shell은 명령을 기본 시스템 셸로 실행한다는 점이에요.
모든 외부 프로그램 실행의 핵심 클래스는 Proc::Async입니다. 프로세스를 비동기로 실행하면서 병행 방식으로 실행 중인 프로세스와 상호작용할 수 있게 해줘요. 일반적으로는 이런 고수준의 추상 인터페이스로 시스템과 상호작용하는 것이 좋은 습관이에요. 다만 Raku에는 저수준 인터페이스로 시스템과 소통하는 방법도 따로 있어요.
네이티브 API로 운영체제 호출하기
NativeCall API를 쓰면 시스템 라이브러리는 물론 접근 가능한 어떤 라이브러리와도 상호작용할 수 있어요. 이 짧은 튜토리얼에서는 getaddrinfo 같은 시스템 함수를 그 인터페이스로 호출하는 방법을 보여주고, kill 같은 함수도 NativeCall 인터페이스로 선언해서 접근할 수 있어요.
다행히 모든 네이티브 함수를 직접 이렇게 만들 필요는 없어요. Butterfly 프로젝트의 일환으로 Elizabeth Mattijsen이 Perl의 함수들을 Raku로 이식하고 있는데, 시스템 함수들도 P5getprotobyname 같은 모듈로 옮기고 있어요. 이 모듈엔 endprotoent, getprotoent, getprotobyname, getprotobynumber, setprotoent 같은 함수가 들어 있죠. 이미 Raku에 있는 그런 함수를 쓰고 싶다면 P5 모듈들을 검색·설치해 보세요.