Interactive Shell과 Non-Interactive Shell: Bash 실행 모드·Startup File 구분

반응형

대화식 명령과 비대화식 명령은 명령 자체의 종류라기보다 shell이 입력을 받는 방식과 실행 환경의 차이다. 같은 grep, wget, Python program도 terminal에서 직접 실행할 수 있고 script나 CI에서 자동 실행할 수도 있다.

그래서 “이 command는 non-interactive tool이다”와 “현재 Bash가 non-interactive shell이다”를 구분해야 한다. 전자는 prompt 없이 automation에 쓰기 좋은 program 특성을 말할 수 있고, 후자는 Bash가 interactive mode로 시작됐는지를 뜻한다.

Interactive Shell이란

GNU Bash 기준으로 option이 아닌 argument와 -c 없이 시작되고 input·error가 terminal에 연결됐거나, -i option으로 시작된 shell이 interactive shell이다. 보통 terminal app을 열어 prompt에서 명령을 입력하는 상황이 여기에 해당한다.

interactive shell에는 사람이 조작하기 위한 동작이 기본으로 따라온다.

  • prompt 표시
  • job control 기본 활성화
  • alias expansion
  • command history
  • 사용자가 입력을 고칠 수 있는 line editing
  • 일부 오류 뒤에도 session 지속

반면 script file이나 bash -c 'command'로 실행되는 Bash는 보통 non-interactive다. command를 미리 정한 뒤 사람이 중간에 답하지 않아도 끝까지 실행할 수 있어야 한다.

현재 Bash가 interactive인지 확인하기

Bash startup script 안에서는 special parameter $-i가 있는지 확인하는 방법이 가장 직접적이다.

case $- in
  *i*) printf '%s\n' 'interactive shell' ;;
  *)   printf '%s\n' 'non-interactive shell' ;;
esac

한 줄 조건으로도 쓸 수 있다.

[[ $- == *i* ]] && printf '%s\n' 'interactive'

test -t 0 또는 [[ -t 0 ]]은 standard input이 terminal인지 확인한다. 유용하지만 shell의 interactive flag 자체와 동일하지는 않다. input redirection, pseudo-terminal, bash -i 조합에 따라 둘이 다를 수 있다.

if [[ -t 0 ]]; then
  printf '%s\n' 'stdin is a terminal'
else
  printf '%s\n' 'stdin is not a terminal'
fi

PS1의 존재 여부도 흔히 쓰이지만 사용자가 임의로 설정할 수 있다. Bash mode 판정이 목적이면 $-를 우선한다.

Interactive와 Login은 서로 다른 축이다

login shell은 login session의 첫 shell처럼 시작된 경우를 말한다. interactive 여부와는 별개의 특성이다.

실행 형태 Interactive Login
일반 terminal의 Bash session 대개 Yes terminal 설정에 따라 다름
bash로 연 nested shell Yes No
bash script.sh No No
bash -c 'printf ok' No No
bash --login -c 'printf ok' No Yes
bash -il Yes Yes

macOS의 기본 login shell은 현재 zsh일 수 있으므로 Bash startup file 규칙을 그대로 zsh에 적용하면 안 된다. 실행 중인 shell과 invocation option을 먼저 확인한다.

Bash Startup File이 달라지는 이유

Bash의 대표적인 startup 흐름은 다음과 같다.

  • interactive login: /etc/profile 뒤에 ~/.bash_profile, ~/.bash_login, ~/.profile 중 처음 발견한 파일
  • interactive non-login: ~/.bashrc
  • non-interactive: 일반적으로 위 파일을 자동으로 읽지 않고, BASH_ENV가 설정됐다면 그 파일을 읽음
  • sh 이름이나 POSIX mode로 호출: 별도의 규칙 적용

SSH remote command는 구현과 호출 방식에 따른 예외가 있어 ~/.bashrc가 읽힐 수도 있다. 핵심은 startup file이 항상 같은 순서로 읽힌다고 가정하지 않는 것이다.

PATH, alias, shell function을 ~/.bashrc에만 넣고 CI·cron·SSH command에서도 당연히 보일 것이라 기대하면 “terminal에서는 되는데 automation에서는 실패”하는 문제가 생긴다.

자동화에서 실패하는 대표 패턴

사용자 입력을 기다린다

read, password prompt, confirmation 질문이 있으면 CI가 멈출 수 있다. 가능한 command에는 명시적인 non-interactive option을 사용하고, 필요한 값은 검증된 argument나 secret channel로 전달한다.

TTY가 있다고 가정한다

color, pager, cursor control, terminal width에 의존한 output은 log parser를 깨뜨릴 수 있다. --no-color, --no-pager 같은 option이 있으면 automation에서 명시한다.

Alias와 개인 PATH에 의존한다

interactive startup file에서만 정의한 alias는 script contract가 아니다. script에서는 실제 executable과 option을 적고, 필요한 PATH를 실행 환경에서 명시한다.

오류를 눈으로만 확인한다

non-interactive job은 exit status와 stderr가 interface다. command 성공 여부를 출력 문구 하나로 추측하지 않고 exit code를 확인하고 log에 context를 남긴다. log severity를 정하는 기준은 Log Level과 작성 기준으로 이어서 볼 수 있다.

sudo가 password를 물어본다

무인 실행에서 sudo prompt를 기다리게 하지 않는다. 필요한 권한 자체를 줄이고, 정말 필요한 privileged operation은 별도 runner·policy로 제한한다. password를 command line에 넣어 우회하는 방식은 피한다.

CI용 Shell Script 점검표

#!/usr/bin/env bash
set -Eeuo pipefail

main() {
  command -v curl >/dev/null 2>&1 || {
    printf '%s\n' 'curl is required' >&2
    return 127
  }

  curl --fail --silent --show-error --location \
    --output artifact.json \
    'https://example.com/artifact.json'
}

main "$@"
  • set -e만으로 모든 오류가 안전하게 처리된다고 단정하지 않는다.
  • variable은 quote하고 임시 file·cleanup·retry policy를 설계한다.
  • command가 stdin을 소비하는지 확인한다.
  • timeout을 정하고 실패가 무한 대기로 바뀌지 않게 한다.
  • output과 exit status를 함께 test한다.
  • interactive helper와 reusable script logic을 분리한다.

명령을 찾고 결과를 좁히는 실제 예시는 grep 명령어 실전 사용법에서 볼 수 있다.

자주 묻는 질문

Shell script는 항상 non-interactive인가

보통 bash script.sh는 non-interactive지만 -i로 강제할 수 있다. 다만 automation script를 interactive mode에 의존하게 만들면 startup file과 사용자 설정의 영향을 크게 받는다.

stdin이 TTY면 무조건 interactive shell인가

아니다. TTY 연결 여부와 Bash의 interactive option은 관련은 있지만 같은 값이 아니다. $--t를 목적에 맞게 따로 확인한다.

wget을 non-interactive tool이라고 부르는 이유는 무엇인가

사용자에게 매 단계 질문하지 않고 option과 exit status로 동작을 제어하기 쉽다는 program 특성을 가리키는 표현이다. wget을 terminal에서 실행했다고 해서 그 tool의 자동화 친화성이 사라지는 것은 아니다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글