리눅스 시스템에서 특정 패키지를 설치하거나 프로그램 실행 중 yes
와 같은 입력을 요구받는 경우가 종종 있다. 그러나 이러한 작업을 shell script로 자동화해야한다면 어떻게 해야할까?? expect
를 활용하면 입력 자동화를 쉽게 구현할 수 있다.
expect
expect
는 커맨드 대화를 자동화하도록 하는 Linux 모듈의 하나이다. telnet
이나 ftp
와 같이 사용자와 상호작용하는 프로그램에서(interactive), 특정 문자열을 기다리고(expect), 정해진 문자열을 자동으로 보내는(send) 처리를 하는 스크립트 언어이다.
expect의 주요 기능
- 자동화된 터미널 상호작용 :
expect
사용자로부터 입력을 요구하는 프로그램을 자동으로 실행할 수 있다. - 패턴 매칭 :
expect
는 프로그램의 출력을 모니터링하고, 특정 패턴을 인식하여 그에 대한 반응을 정의할 수 있다. 이를 통해 다양한 상황에 맞춰 스크립트를 작성할 수 있다. - 조건부 로직 :
expect
스크립트 내에서 조건문을 사용하여 프로그램의 출력에 따라 다른 행동을 취할 수 있다.
expect 설치하기
expect
스크립트를 사용하려면, expect
모듈이 설치되어 있어야한다.
# ubuntu
$ sudo apt-get install -y expect
# macOS
$ brew install expect
설치확인
$ expect -v
expect version 5.45
expect 사용법
command | 설명 |
---|---|
expect | expect 스크립트로, 응답을 읽어서 매칭시킬때 사용한다.패턴 매치는 switch문, case문과 동일한 처리를 실현할 수 있다. |
spawn | expect 내에서 프로세스를 생성하는 커맨드이다. |
send | 머신에 문자열에 응답하는 커맨드이다. (입력하는 커맨드) |
exit | expect의 처리를 종료시킨다. |
expect
는 여러가지 방식으로 사용할 수 있다. 그 중 대표적인 2가지를 살펴보자.
- 첫번째는
#!/usr/bin/expect
로 시작하는 스크립트 파일을 작성하는 것이다. - 두번째는
expect -c "..."
형태로 코드를 한 줄로 실행하는 것이다.
expect 스크립트 예제
ssh를 통해 원격 서버에 자동으로 로그인하는 스크립트를 작성해보자. 다음 스크립트는 spawn
명령어를 사용하여 ssh 세션을 시작하고, expect
명령어로 password:
프롬프트를 기다린다. 비밀번호를 입력한 후 interact
를 사용하여 사용자에게 제어를 넘긴다.
#!/usr/bin/expect
set timeout 20
set host "my.server.com"
set user "my_username"
set password "my_password"
spawn ssh $user@$host
expect "password:"
send "$password\\r"
interact
이외에도, 이전에 프로젝트에서 expect
를 사용한 경험이 있다. 공모전에서 OCI를 사용하며, OCI CLI 로그인을 자동화하는 것이 필요했다. oci setup config
의 질문 패턴을 파악해서, 각 질문마다 적절한 input이 이루어지도록 구성했다. 하나의 스크립트 파일에서 expect
스크립트 뿐만 아니라 다른 명령어들도 실행해야 한다면 다음과 같이 expect -c
의 형식을 활용할 수 있다.
#======================= oci configure ; automation using expect =======================
expect -c "
spawn $HOME/bin/oci setup config
expect \\"Enter a location for your config\\"
send -- \\"$HOME/.oci/config\\r\\"
expect \\"Enter a user OCID\\"
send -- \\"{{ .Values.oci.user_ocid }}\\r\\"
expect \\"Enter a tenancy OCID\\"
send -- \\"{{ .Values.oci.tenancy_ocid }}\\r\\"
expect \\"Enter a region\\"
send -- \\"{{ .Values.oci.bucket_region }}\\r\\"
expect \\"Do you want to generate a new API Signing RSA key pair?\\"
send -- \\"n\\r\\"
expect \\"Enter the location of your private key file\\"
send -- \\"{{ .Values.oci.api_key_path }}\\r\\"
expect eof
"
이처럼 expect는 반복적인 입력 작업을 자동화하는 데 정말 유용하게 사용할 수 있다.