[minishell] 4. 종료상태와 에러메세지 처리

모든 명령어는 종료 상태(exit status) 리턴한다. 명령어 성공시에는 0을 리턴하고 실패시에는 에러 코드로 해석될 수 있는 1~255를 리턴한다. 즉 유닉스 관례를 잘 따르는 프로그램이라면, 함수의 가장 마지막에 실행된 명령어가 종료 상태를 결정한다.

1. 종료 상태(exit status)와 $? 변수

모든 명령어는 종료 상태(exit status) 리턴한다. 명령어가 성공시에는 0을 리턴하고 실패시에는 에러 코드로 해석될 수 있는 non-zero(1~255)를 리턴한다. 마찬가지로 유닉스 관례를 잘 따르는 프로그램, 스크립트 등 이라면, 함수의 가장 마지막에 실행된 명령어가 종료 상태를 결정한다. 출처arrow-up-right

$? 변수는 제일 마지막 명령어의 종료 상태 코드 값을 가진다. bash에서는 이렇게 해서 함수의 리턴값을 돌려주는 것이다.

상단의 터미널 이미지 참고 !

2. 종료 상태 코드(exit status code)

몇몇 종료 상태 코드들은 예약되어 있기 때문에 사용자가 임의로 exit 의 매개변수로 쓰면 안 된다. 흔히 프로그램에서 에러 발생시 종료를 위해 exit 1을 쓰는데, 이는 다양한 형태의 에러를 나타내기 때문에 맞는 사용이기도 하지만, 다른 면에서 보면 에러에 대한 유용한 정보를 나타내지 않는다는 것도 의미한다.

표 출처arrow-up-right

종료 코드

에러메세지

0

성공적으로 실행

1

광범위한 일반적 에러

“Operation not permitted” , "not a valid identifier", "too many arguments" 등

2

쉘 builtin 명령어의 오사용

“No such file or directory” 등

126

Permission 문제로 실행 불가능한 명령어의 구동

"Permission denied", "Is a directory"

127

명령어의 경로($PATH) 문제 혹은 명령어 오타

“Command not found”, “No such file or directory”

130

치명적 에러 발생으로 인한 종료 (Ctrl+C)

"Script terminated by Ctrl+C”

255

exit 에 정수(0~255)가 아닌 인자 넘김

"numeric argument required"

3. strerror(errno) 로 에러 메세지 출력하기

42 minishell 과제는 기본적으로 bash를 따르는 것을 원칙으로 하기 때문에 bash의 에러 메세지라고도 볼 수 있다.

현실적으로 미니쉘을 구현하면서, 종료 코드에 맞는 모든 에러 메세지를 미리 설정해 출력하는 건 불가능하다. bash의 모든 에러 상황을 테스트 해볼수는 없기 때문이다.

그럴때 사용하라고 주어진 허용함수가 char *strerror(int errno); 이다. strerrorarrow-up-right를 통해 에러 번호(errno)와 에러 메세지 문자열을 얻을 수 있다. 아래처럼 테스트 해보니 c에서 errno 변수와 그에 맞는 메세지는 총 108개 내장되어 있는 것 같다.

프로그램 실행 결과

몇 가지 익숙한 에러 메세지들도 보인다. 이제 미니쉘에서 아래 코드 처럼 라고 일일이 에러 메세지를 정의해 줄 필요 없이,

아래 코드 처럼 가능한 상태코드의 에러메세지는 strerror 함수를 통해 출력시키는게 좋을 것 같다.

4. minishell의 에러 메세지와 $?

strerror(errno)로 출력 가능한 에러 메세지들은 다 출력해주고, strerror에 정의되어있지 않은 특이한 에러 메세지들은 직접 테스트해보고 넣어줘야한다. minishell 테스터를 참고하면 어떤 에러메세지가 어떤 상황에 발생하는지 알 수 있다.

예를 들면 아래 메세지들은 흔하게 발생하지만 정의되어 있지 않다.

  • "not a valid identifier" (1)

    • export 첫 번째 인자=을 띄어 쓴 경우

    • export 인자에 숫자가 포함된 경우

    • unset 인자에 숫자가 포함된 경우

    • -> export, unset 수정

      • print_identifier_err()

  • "too many arguments" (1)

    • exit 인자 많을 때

      • minishell: exit: too many arguments

      • print_execute_err_1()

  • “Command not found", (127)

    • 이상한 input 들어왔을 때

      • minishell: asdasdsdsad: command not found

      • print_execute_err_1

  • "numeric argument required" (255)

    • exit 에 정수가 아닌 인자를 넘긴 경우

      • minishell: exit: iiii: numeric argument required

      • print_execute_err_2()

나는 그래서 아래 4개의 함수를 만들어 에러 관련한 메세지들을 모두 처리했다.

  1. print_identifier_err()

    • 환경변수 인자 관련 에러 출력할 함수

  2. print_execute_err_1()

    • 명령어 실행 관련해서 범용으로 사용할 함수

    • 에러 메세지에 프로그램 이름과 명령어 이름, 에러메세지가 들어감

  3. print_execute_err_2()

    • 명령어 실행 관련해서 범용으로 사용할 함수

    • 에러 메세지에 프로그램 이름과 명령어 이름, 명령어 다음 인자, 에러메세지가 들어감

  4. print_errno_err()

    • exit(EXIT_FAILURE) 하고 strerror(errno) 출력할 함수

5. bash의 에러 메세지 특이 케이스

5.1. 종료코드(1)

1. ls 옵션을 잘못 사용한 경우

2. export 첫 번째 인자=을 띄어 쓴 경우

  • export 인자=인자 혹은 export 인자= 인자 만 가능

3. export 인자에 숫자가 포함된 경우

  • key 경우에만 해당

  • value에는 숫자가 들어가도 됨

4. 2번과 3번을 동시에 하는 경우

  • 에러메세지 두 개가 나옴

5. exit 정수 인자가 여러 개인 경우

5.2. 종료코드(127)

환경변수 목록에 없는 변수를 인자로 넣은 경우

  • 근데 평가 항목에 인자 안 넣는 것으로..

5.3. 종료코드(255)

exit 에 정수가 아닌 인자를 넘긴 경우

  • 분명 이 글 부록 C. 특별한 의미를 갖는 종료 코드arrow-up-right에서는 exit에 잘못된 인자를 넘겼을 때 종료 코드로 128을 넘겨야 된다고 나오는데, 아무리 bash에서 테스트 해봐도 255가 나온다. 출처가 오래된 자료거나 bash가 업데이트 된 것 같다.

  • exit code 128, what's the reason?arrow-up-right 나랑 비슷한 질문을 한 구글링 자료가 있어서 찾아보니, If n is not an unsigned decimal integer, or is greater than 255, the results(exit status) are unspecified. 출처arrow-up-right 라고 한다. 즉, 쉘 마다 버전 마다 다를 수 있다는 것 같다.

  • 우리 minishell 에서는 exit(255)로 구현하면 될 것 같다.

Last updated

Was this helpful?