[minishell] 4. 종료상태와 에러메세지 처리
모든 명령어는 종료 상태(exit status) 리턴한다. 명령어 성공시에는 0을 리턴하고 실패시에는 에러 코드로 해석될 수 있는 1~255를 리턴한다. 즉 유닉스 관례를 잘 따르는 프로그램이라면, 함수의 가장 마지막에 실행된 명령어가 종료 상태를 결정한다.
1. 종료 상태(exit status)와 $?
변수
$?
변수모든 명령어는 종료 상태(exit status)
리턴한다. 명령어가 성공시에는 0을 리턴하고 실패시에는 에러 코드로 해석될 수 있는 non-zero(1~255)를 리턴한다. 마찬가지로 유닉스 관례를 잘 따르는 프로그램, 스크립트 등 이라면, 함수의 가장 마지막에 실행된 명령어가 종료 상태를 결정한다. 출처
$?
변수는 제일 마지막 명령어의 종료 상태 코드 값을 가진다. bash에서는 이렇게 해서 함수의 리턴값을 돌려주는 것이다.
상단의 터미널 이미지 참고 !
2. 종료 상태 코드(exit status code)
몇몇 종료 상태 코드들은 예약되어 있기 때문에 사용자가 임의로 exit 의 매개변수로 쓰면 안 된다. 흔히 프로그램에서 에러 발생시 종료를 위해 exit 1
을 쓰는데, 이는 다양한 형태의 에러를 나타내기 때문에 맞는 사용이기도 하지만, 다른 면에서 보면 에러에 대한 유용한 정보를 나타내지 않는다는 것도 의미한다.
종료 코드
뜻
에러메세지
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);
이다. strerror를 통해 에러 번호(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개의 함수를 만들어 에러 관련한 메세지들을 모두 처리했다.
print_identifier_err()
환경변수 인자 관련 에러 출력할 함수
print_execute_err_1()
명령어 실행 관련해서 범용으로 사용할 함수
에러 메세지에 프로그램 이름과 명령어 이름, 에러메세지가 들어감
print_execute_err_2()
명령어 실행 관련해서 범용으로 사용할 함수
에러 메세지에 프로그램 이름과 명령어 이름, 명령어 다음 인자, 에러메세지가 들어감
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. 특별한 의미를 갖는 종료 코드에서는 exit에 잘못된 인자를 넘겼을 때 종료 코드로 128을 넘겨야 된다고 나오는데, 아무리 bash에서 테스트 해봐도 255가 나온다. 출처가 오래된 자료거나 bash가 업데이트 된 것 같다.
exit code 128, what's the reason? 나랑 비슷한 질문을 한 구글링 자료가 있어서 찾아보니, If n is not an unsigned decimal integer, or is greater than 255, the results(exit status) are unspecified. 출처 라고 한다. 즉, 쉘 마다 버전 마다 다를 수 있다는 것 같다.
우리 minishell 에서는 exit(255)로 구현하면 될 것 같다.
Last updated