1. 유닉스 시스템 프로그래밍 개요
1-1. 개요
UNIX system programming 은 유닉스에서 제공하는 System call을 이용해서 프로그램을 작성하는 것이다.
시스템호출은 유닉스 시스템이 제공하는 서비스를 프로그램에서 이용할 수 있도록 지원하는 프로그래밍 인터페이스를 의미한다. 유닉스에서 동작하는 프로그램을 작성하려면 간단한 프로그램을 제외하고는 대부분 시스템 호출을 이용해야한다.
1-2. 유닉스 시스템 표준
역사
유닉스는 1969년에 미국의 통신회사인 AT&T 산하의 벨연구소(Bell laboratory)에서 Ken Thompson과 Dennis Ritchie가 개발한 운영체제(Operating System,OS)이다.
처음에는 Assembly language로 개발했고, 데니스 리치가 개발한 C언어를 이용해 1973년에 다시 만들어서 high-level language로 작성된 최초의 운영체제가 되었다. 초기에 source code가 공개되어 대학교나 기업에서 쉽게 이용할 수 있었고 다양한 기능이 추가되었다.
AT&T의 상용 유닉스(시스템V)와 버클리 대학의 BSD(Berkeley Software Distribution)계열로 나뉘어 발전해왔다. BSD버전에는 네트워크 기능의 추가가 주목할만하다.
현재는 1989년에 AT&T, Sun Microsystems가 위 두계열의 장점을 결합한 형태로 공동 개발한 SVR4가 대부분 유닉스의 기반이 되고 있다. 대표적인 예로는 썬의 솔라리스 2.x, HP의 HP-UX 10.x 이다.
유닉스 시스템에서 C로 작성한 프로그램의 호환성을 보장하기 위한 여러가지 표준이 존재한다. SVR4는 표준을 준수하고 있다.
유닉스 시스템 프로그래밍 관련 표준 종류
ANSI C 표준
ANSI(american national standards institute)는 미국 표준 협회이다. 국제적으로 영향력있는 표준을 정하고 있다. 이 협회에서 표준화한 C언어 명세가 ANSI C 표준이다. C언어의 문법, 라이브러리, 헤더 파일을 정의하고 있다. ANSX3.159-1989로 등록된 상태이며 국제 표준 기구 ISO(International Standardization Organization)에서 받아들여 ISO/IEC 9899:1990으로 발표했다. http://www.iso.org 에서 비용을 지불하고 표준을 구할 수 있다.
POSIX (Portable Operation System Interface)
파직스라고 발음한다. 유닉스에 기반을 둔 일련의 표준 운영체제 인터페이스이다.
서로 다른 유닉스 시스템 간의 상호 이식이 가능한 응용 프로그램을 개발하기 위한 표준이다.
IEEE에서 정의한 규격으로 유닉스 시스템의 공통 응용 프로그래밍 인터페이스 (API, Application Programming Interface)를 정리했다.
POSIX의 마지막 글자 X는 유닉스 호환 운영체제에 X가 붙는데서 유래했다.
POSIX.1, POSIX.2 등이 있고 POSIX.1의 정보는 http://www.unix.org 에서 찾을 수 있다.
X/Open 가이드
1984년 유럽의 유닉스 시스템 제조업체를 중심으로 설립된 단체이며, 개방 시스템에 대한 표준을 정의/보급하는 일을 한다. 특히 유닉스 시스템에서 응용 프로그램의 이식성을 높이는 것이 초기 목표였다. X/Open이식성 가이드(XPG, X/OPEN portability Guide)를 발표했다. X/Open은 1996년에 오픈 소프트웨어 재단과 합병해 The Open Group으로 변경되었고 UNIX에 대한 상표권을 소유중이다.
시스템V 인터페이스 정의 (SVID, System V Interface Definition)
UNIX의 시스템V의 인터페이스를 정의한다. 프로그램과 장치에서 이용할 수 있는 시스템 호출과 C라이브러리의 표준을 포함한다. POSIX와 X/Open의 작업은 SVID에 부분적으로 기반을 두고 있고 이 표준을 준수하면 하드웨어에 독립적인 프로그래밍을 할 수 있다.
단일 유닉스 규격(SUS, single unixt specification)
컴퓨터 운영체제가 유닉스라는 이름을 사용하기 위해 지켜야하는 표준의 총칭. SUS는 IEEE와 The Open Group의 표준화 작업 결과물에 바탕을 두고 있다. The Austin Group이 개발, 유지관리를 담당한다. 1980년대 중반에 유닉스 시스템 인터페이스를 표준화하기 위한 프로젝트에서 출발했고 1998년에 The Austing Group에서 SUSv3 표준을 개발하여 2002년에 발표했다.
SUSv3에는 C언어의 헤더 파일 규격, 쉘과 명령어 규격, 시스템 호출 규격이 포함되어있다.
1-3. 유닉스 시스템 프로그래밍이란?
유닉스 자체가 C언어로 대부분 구현되어있다.
유닉스 시스템 프로그래밍이란 Application Programming과 달리 유닉스에서 제공하는 System call을 사용해 프로그램을 작성하는 것이다.
시스템 호출과 라이브러리 함수
시스템 호출이란 파일 시스템 접근, 사용자 정보, 시스템 정보, 시스템 시간 정보, 네트워킹 등의 UNIX에서 제공하는 서비스를 이용해 프로그램을 구현할 수 있도록 만들어진 프로그래밍 인터페이스이다. 시스템 호출을 이용하면 유닉스 시스템의 서비스를 직접 이용하는 프로그램을 만들 수 있다.
- 시스템 호출의 형태
리턴값 = 시스템 호출(인자,...);
함수명처럼 시스템 호출에 사용할 이름이 정의되어 있다. 대부분은 호출결과의 성공실패를 나타내는 정수값을 리턴한다.
- 라이브러리 함수
라이브러리는 미리 컴파일된 함수들을 묶어서 제공하는 특수한 형태의 파일이다. 라이브러리 함수는 라이브러리에 포함된 함수를 의미한다. 이것을 만든 이유는 자주 사용하는 기능을 독립적으로 구현해서, 프로그램의 개발과 디버깅을 쉽게 하고 컴파일을 좀더 빠르게 할 수 있기 때문이다.
유닉스에서 라이브러리는 /lib 나 /usr/lib에 위치한다.
라이브러리 파일명은 lib로 시작되고 '.a'나 '.so'의 확장자를 가진다.
- lib.a : 정적 라이브러리(Static library)
정적 라이브러리는 프로그램을 컴파일할 때 같이 적재되어 실행 파일을 구성한다. 실행파일에 라이브러리 코드가 포함되므로 크기가 커질 수 있다.
- lib.so : 공유 라이브러리 (Shared library)
공유 라이브러리는 실행파일에 포함되지 않는다. 공유 라이브러리를 이용해 생성한 실행 파일은 실행 시에 해당 라이브러리가 메모리에 적재된다.
이렇게 적재된 라이브러리는 다른 실행 파일에서도 공유 가능하다. 최근에는 메모리를 효율적으로 사용하기 위해 공유라이브러리를 많이 사용한다.
시스템 호출과 라이브러리의 비교
응용 프로그램은 시스템호출과 라이브러리를 이용하여 작성할 수 있다.
시스템 호출은 커널의 해당 모듈을 직접 호출해서 작업하고 결과를 리턴한다.
커널, 즉 시스템을 직접 호출하기 때문에 시스템호출이라고 한다.
라이브러리는 커널 모듈을 직접 호출하지 않고, 라이브러리 함수에서 커널의 서비스를 이용할 때는 함수 내부에서 시스템 호출을 사용한다.
시스템 호출과 라이브러리 함수의 기본 형식과 사용법이 유사해서 구별이 어려울 수 있다.
유닉스에서 제공하는 man의 위치와 오류 처리 방법을 잘 살펴보면 구별이 가능하다.
man 페이지 위치
유닉스 시스템은 다양한 서비스에 대한 맨 페이지를 제공한다. man 페이지는 종류에 따라 섹션이 구분되어 있다.
종류 | 정의 |
---|---|
섹션1 | 유닉스에서 사용하는 일반적인 명령 |
섹션2 | 시스템 호출 |
섹션3 | 라이브러리 함수 |
예를 들어 open은 시스템 호출 중 하나이며 이것에 대한 설명을 보면 상단에 System call이라고 나오고 open(2)로 표시된다. (2)가 섹션2라는 의미이다.
명령의 이름이 함수명과 같은 경우도 있다. uname은 명령도 있고 시스템 호출도 있다. man uname 을 입력하면 명령(섹션 1)에 관한 설명만 볼 수 있다.
man 명령은 기본적으로 섹션1의 내용만 출력하기 때문이다. 섹션2의 설명을 보려면 다음과 같이 입력해야한다.
# man -s 2 uname
- 오류 처리 방법
시스템 호출은 성공적으로 수행시 0을 호출한다. 실패하면 -1을 리턴하고, 전역변수 errno에 errer code를 저장한다.
각 시스템호출의 오류코드는 맨페이지에 나타나있다.
실행파일명은 소스파일명에서 .c 확장자를 .out 으로 교체한 형태로 지정한다.
시스템 호출 오류 처리하기
unix.txt 파일의 존재유무를 access 함수로 확인하는 예제.
<ex1_1.c>
#include <unistd.h>
#include <stdio.h>
extern int errno;
int main(void) {
if (access("unix.txt", F_OK) == -1) {
printf("errno=%d\n", errno);
}
return 0;
}
<커맨드 라인에서 실행파일 실행>
# ex1_1.out
errno=2
실행파일 실행결과 errno=2라는 결과를 얻었는데, 이 값은 sys/errno.h에서 확인가능하다.
# vi /usr/include/sys/errno.h
위 실행파일 로직 중 access함수는 System call이며 man access 명령으로 해당함수의 오류코드와 해당 설명을 확인할 수 있다.
라이브러리 함수는 오류가 발생한 경우 NULL을 리턴하는데 경우에 따라 리턴값이 int형으로 지정되어있으면 -1을 리턴한다. 시스템 호출과 마찬가지로 errno 변수에 오류 코드를 저장한다.
- 라이브러리 함수 오류 처리하기
<ex1_2.c>
#include <stdlib.h>
#include <stdio.h>
extern int errno;
int main(void) {
FILE *fp;
if((fp = fopen("unix.txt","r")) == NULL){
printf("errno=%d\n",errno);
exit(1);
}
fclose(fp);
return 0;
}
<결과>
#ex1_2.out
errno=2
fopen함수에서 발생할 수 있는 오류코드도 맨 페이지에서 찾아볼 수 있다.
1-4. 유닉스 시스템 도구
유닉스 기본 명령
시스템 접속, 파일, 디렉토리에 관한 것.
- 로그인/로그아웃
명령 | 기능 | 주요옵션 | 사용 예 |
---|---|---|---|
telnet | 유닉스 시스템 접속 | telnet hanb.co.kr |
- 파일/디렉토리
명령 | 기능 | 주요옵션 | 사용 예 |
---|---|---|---|
pwd | 현재 디렉토리 경로 출력 | - | |
ls | 디렉토리 내용 출력 | -a : 숨김파일 출력, -l : 상세정보 출력 | ls -a /tmp |
cd | 현재 디렉토리 변경 | - | cd ~user1 |
cp | 파일/디렉토리 복사 | -r : 디렉토리 복사 | cp a.txt b.txt, cp -r dir1 dir2 |
mv | 파일/디렉토리 이름 변경과 이동 | - | mv a.txt b.txt |
rm | 파일/디렉토리 삭제 | -r : 디렉토리 삭제 | rm -r dir1 |
mkdir | 디렉토리 생성 | mkdir dir1 | |
rmdir | 빈 디렉토리 삭제 | - | |
cat | 파일 내용 출력 | - | |
more | 파일 내용을 페이지 단위로 출력 | - | more a.txt |
chmod | 파일 접근 권한 변경 | - | chmod 755 a.exe , chmod go+x a.exe |
grep | 패턴 검색 | - | grep abcd a.txt |
- 프로세스 관련 명령
명령 | 기능 | 주요옵션 | 사용 예 |
---|---|---|---|
ps | 현재 실행중인 프로세스의 정보 출력 | -ef : 모든 프로세스에 대한 상세 정보 출력 | ps -ef , ps -ef 파이프 grep ftp |
kill | 프로세스 강제 종료 | -9 강제종료 | kill 5000, kill -90 5001 |
- 기타 명령
명령 | 기능 | 주요옵션 | 사용 예 |
---|---|---|---|
su | 사용자 계정 변경 | - : 변경할 사용자의 환경 초기화 파일 실행 | su - , su - user01 |
tar | 파일/디렉토리 묶기 | cvf : tar 파일 생성, tvf : tar 파일 내용 보기, xvf : tar 파일 풀기 | tar cvf a.tar *, tar tvf a.tar, tar xvf a.tar |
whereis | 파일 위치 검색 | - | whereis ls |
which | 파일 위치 검색 | - | which telnet |
- vi 편집기 내부 명령
vi는 유닉스 시스템에서 사용하는 기본 문서 편집기이다.
# vi test.c
기능 | 명령 |
---|---|
입력모드로 전환 | i,a,o,O |
명령모드로 전환 | esc키 |
커서이동 | j,k,h,l 또는 방향키 |
행이동 | #G (50G, 143G ..), :행번호 |
한글자 수정 | r |
여러 글자 수정 | #s(5s,7s ..) |
단어 수정 | cw |
명령취소 | u, U |
검색해서 수정 | :%s/aaa/bbb/g |
복사 | #y (5yy, 10yy) |
붙이기 | p |
커서 이후 삭제 | D (대문자D) |
글자 삭제 | x, #x(3x..) |
행 삭제 | dd, #dd (3dd..) |
저장하고 종료 | :wq! 또는 ZZ |
저장없이 종료 | :q! |
행붙이기 | J (대문자J) |
화면 갱신 | ctrl+L |
행번호 보이기 | :set nu |
행번호 숨기기 | :set nonu |
컴파일 환경
작성한 프로그램을 실행하려면 컴파일이 필요하다.
컴파일이란 텍스트로 작성한 프로그램을 기계어(machine language)로 변환하는 과정이다. 보통 컴파일 과정과 라이브러리 링크 과정을 묶어서 수행하는 것을 의미한다.
- 컴파일 과정
test.c (컴파일) => test.o (기계어로 변환한 오브젝트 파일) => test.o+printf.o (로직에 있는 라이브러리 함수의 오브젝트 파일과 링크) => a.out (실행파일)
- GNU C 컴파일러 : gcc
프로그램을 컴파일하려면 이를 수행하는 컴파일러가 설치되어있어야한다. 썬 마이크로 시스템즈의 솔라리스는 C 컴파일러를 별도로 판매중이다. GNU C는 ANSI C와 호환성이 있다. 솔라리스용 GNU C 컴파일러는 여기에서 무료로 구할 수 있다.
GNU C 컴파일러의 명령은 gcc
이다.
gcc
- 기능: C 프로그램을 컴파일해 실행 파일을 생성한다.
- 형식 : gcc [옵션] [파일명]
옵션 '-c' : 오브젝트 파일(.o)만 생성한다. '-o' 실행파일명: 지정한 이름으로 실행 파일을 생성한다. 기본 실행 파일명은 a.out 이다.
사용 예
gcc test.c
gcc -c test.c
gcc -o test test.c
- gcc는 /usr/local/bin 디렉토리에 설치된다. 사용자 환경 설정 파일에서 해당 경로를 추가해야한다. 콘 쉘(ksh) 환경을 사용할 경우 ~/.profile에 추가해야한다.
#vi ~/.profile
...
PATH=$PATH:/usr/local/bin
export PATH
- 경로 추가후 사용자 환경 설치 파일을 실행해서 변경사항을 적용해야한다. 본쉘, 콘쉘은 '.' 명령을 이용한다.
$ . ~/.profile
- gcc로 컴파일하면 'XXX.out' 실행파일이 생성된다. 실행파일명을 입력하면 프로그램이 실행된다. 또는 위치한 디렉토리경로를 포함하여 적어서 실행하면 된다.
Makefile과 make
프로그램 작성시 소스 파일이 여러개인 경우 이를 묶어서 실행 파일을 생성할 수 있는 명령인 make와 Makefile 설정파일이 있다.
Makefile : 컴파일 명령, 소스 파일을 컴파일하는 방법, 링크할 파일들, 실행 파일명을 설정하는 파일이다.
make : Makefile을 읽고 해당 파일에서 지정한 대로 컴파일을 실행하고 실행 파일을 생성한다. 실행파일을 한번 생성하면 변경사항이 있는 파일만 재컴파일한다. /usr/ccs/bin 디렉토리에 있으므로 사용자 환경 설정의 경로에 추가하는 것이 좋다.
$ vi ~/.profile
....
PATH=$PATH:/usr/local/bin:/usr/ccs/bin
export PATH
<ex1_3_main.c>
#include <stdio.h>
extern int addnum(int a, int b);
int main(void){
int sum;
sum = addnum(1,5);
printf("Sum 1~5 = %d\n",sum);
return 0;
}
<ex1_3_addnum.c>
int addnum(int a, int b){
int sum = 0;
for(; a<=b; a++){
sum += a;
}
return sum;
}
- Makefile 내용
CC=gcc1
CFLAGS=2
OBJS=ex1_3_main.o ex1_3_addnum.o3
LIBS=4
all: add5
add: $(OBJS)6
$(CC) $(CFLAGS) -o add $(OBJS) $(LIBS)
ex1_3_main.o: ex1_3_main.c7
$(CC) $(CFLAGS) -c ex1_3_main.c
ex1_3_addnum.o : ex1_3_addnum.c
$(CC) $(CFLAGS) -c ex1_3_addnum.c
clean:8
rm -f $(OBJS) add core
1. 컴파일명령을 gcc로 설정한다. ↩
2. 컴파일 옵션 지정 ↩
3. 생성할 오브젝트 파일명 지정 ↩
4. 표준C 라이브러리 외 다른 라이브러리 지정 ↩
5. 생성할 실행 파일명을 add로 지정 ↩
6. 실행파일을 어떻게 생성할 것인지 지정 ↩
7. 각 오브젝트 파일을 어떻게 생성할 것인지 지정한다. ↩
8. make clean 수행시 실행할 명령을 지정하다. ↩
- 같은 경로에 Makefile, 두개의 프로그램 소스파일을 두고 make 명령을 수행하면 두파일의 실행파일(.o)을 만든다.
# ls
Makefile ex1_3_addnum.c ex1_3_main.c
# make
gcc -c ex1_3_main.c
gcc -c ex1_3_addnum.c
gcc -o add ex1_3_main.o ex1_3_addnum.o
#ls
Makefile add* ex1_3_addnum.c ex1_3_addnum.o ex1_3_main.c ex1_3_main.o
#add
Sum 1~5 = 15
실행파일과 오브젝트파일을 모두 삭제하려면 make clean 명령을 수행하면 된다.
Makefile에 설정한 옵션에 따라 실행파일과 *.o 파일을 모두 삭제한다.
오류 처리 함수
각 오류값의 의미를 보여주는 함수
<오류메세지출력:perror(3) 함수원형>
#include <studio.h>
void perror(const char *s);
<perror() 응용>
#include <sys/errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void){
if(access("unix.txt", R_OK) == -1) {
perror("unix.txt");
exit(1);
}
return 0;
}
<결과>
#ex1_4.out
unix.txt: No such file or directory
perror함수는 errono에 저장된 값을 읽어 이에 해당하는 메세지를 표준 오류로 출력한다.
- strerror(3)
strerror함수는 ANSI C에서 추가로 정의한 함수이다. 함수의 인자로 errno에 저장된 값을받아 오류 메세지를 리턴한다. 리턴된 오류 메세지를 사용자가 적절하게 가공할 수 있다. strerror 함수는 오류 메시지가 저장된 문자열을 가리키는 포인터를 리턴한다.
<함수 원형>
#include <string.h>
char *strerror(int errnum);
<응용>
#include <sys/errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern int errno;
int main(void) {
char *err;
if(access("unix.txt", R_OK) == -1 ){
err = strerror(errno);
printf("오류: %s(unix.txt)\n", err);
exit(1);
}
return 0;
}
<결과>
#ex1_5.out
오류 : no such file or diretory(unix.txt)
동적 메모리 할당
배열은 프로그램이 시작할 때 필요한 메모리를 미리 확보한다. 동적 메모리 할당은 프로그램이 실행하는 도중에 필요한 메모리 공간을 할당하고 더이상 사용하지 않을 때 해당 공간을 해제하는 것이다.
동적 메모리 할당의 장점은 필요한 데이터양에 따라 메모리 공간을 효율적으로 사용할 수 있다.
[메모리 할당 함수 : malloc, calloc, realloc]
- malloc(3) : 지정 크기의 메모리를 할당하는데 성공하면 메모리 시작주소, 실패하면 Null 포인터를 리턴한다.
인자로 지정한 메모리 크기는 바이트 단위이다. malloc 함수는 할당된 메모리를 초기화하지 않는다.
<함수 원형>
#include <stdlib.h>
void *malloc(size_t size);
<사용예: 문자100개를 저장할 수 있는 메모리 할당하기>
char *ptr
ptr = malloc(sizeof(char) * 100);
- calloc(3): 배열요소의 개수(nelem), 각 배열요소의 크기(elsize) 바이트 배열을 저장할 메모리를 할당하고 할당된 메모리를 0으로 초기화한다.
<함수원형>
#include <stdlib.h>
void *calloc(size_t nelem, size_t elsize);
<사용예 : 길이가 20바이트인 요소 10개로 구성된 배열을 저장할 수 있는 메모리를 할당>
char *ptr
ptr = calloc(10,20);
- realloc(3) : 이미 할당받은 메모리에 추가로 메모리를 할당할 때 사용하며 인자값으로할당받은 메모리를 가리키는 포인터(ptr), 할당할 메모리의 크기(size)를 넘긴다.
이 함수는 이전에 할당받은 메모리와 추가할 메모리를 합한 크기의 메모리를 새롭게 할당하고 주소를 리턴한다.
이전 메모리의 내용을 새로 할당된 메모리로 복사한다. realloc 함수로 메모리를 새로 할당받으면 이전 메모리 주소는 필요없다.
<함수원형>
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
<사용예 : malloc함수로 할당받은 메모리에 추가로 100바이트 메모리를 할당>
char *ptr, *new;
ptr = malloc(sizeof(char) * 100);
new = realloc(ptr, 100);
- 메모리 해제 함수 : free(3)
사용을 마친 메모리를 해제하고 반납한다. free함수가 성공하면 ptr이 가리키던 메모리는 의미가 없다.
<함수 원형>
#include <stdlib.h>
void free(void *ptr);
<parameter>
ptr : 해제할 메모리 주소
1-5. 명령행 인자(CLA, Command Line Arguments)
command-line 이란 유닉스시스템에서 사용자가 명령을 입력하는 행을 말한다.
프롬프트가 뜨고 커서가 사용자 입력을 기다리고 있는 행이다.
명령행 인자는 일반적으로 명령의 옵션이나 옵션의 인자, 명령의 인자로 구성된다.
ls 명령의 경우 '-l' 옵션과 특정 디렉터리명을 붙일 수 있는데 이러한 값들을 명령행 인자라고 한다.
명령행 인자의 전달
명령행 인자는 자동으로 프로그램의 main 함수에 전달된다.
int main(void){ ... }
<명령행 인자 값 추가>
int main(int argc, char *argv[]){ ... }
[parameter 설명]
argc : 명령과 인자를 포함한 개수이며, 두번째 인자 배열의 크기이다.
argv : 명령과 각 인자를 담고 있는 배열.
명령행 인자는 argv에 문자열 형태로 저장된다.
<명령행 인자 출력 함수>
#include <stdio.h>
int main(int argc, char *argv[]){
int n;
printf("argc = %d\n", argc);
for(n = 0; n <argc; n++)
printf("argv[%d] = %s\n", n, argv[n]);
return 0;
}
<결과>
#ex1_6.out -h 100
argc = 3
argv[0] = ex1_6.out
argv[1] = -h
argv[2] = 100
옵션처리 : getopt(3)
명령행인자로 전달된 옵션을 편리하게 처리할 수 있다. 이 함수의 man 페이지를 보면 표준에 따라 관련 헤더 파일이 다름을 알 수 있다.
SVID3, XPG3
#include <stdio.h>
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
POSIX.3, XPG4, SUS, SUSv2, SUSv3
#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
[parameter 설명]
optstring : 해당 실행 파일에서 사용할 수 있는 옵션을 나타내는 문자.
옵션에 인자가 있으면 ":"를 붙여서 지정한다.
사용 가능한 옵션이 -a, -b, -c 인 경우 optstring에 "abc"로 지정하면 된다.
이 중에 -c 옵션에 -c name 과 같이 옵션에 인자가 있으면 "abc:"로 지정한다
유닉스 명령 기본 규칙
getopt 함수로 옵션을 처리하려면, 유닉스 명령에 대한 Basic Utility Syntax Guideline 을 준수해서 명령행 인자를 입력해야한다.
명령어에 대한 기본 규칙은 "man intro"로 확인할 수 있다.
기본규칙은 13개 항목이고 확장 규칙은 8개 항목이다.
이중에 getopt 함수와 관련이 있는 항목은 다음과 같다.
기본 규칙
[규칙 3] 옵션의 이름은 한글자여야한다.
[규칙 4] 모든 옵션의 앞에는 하이픈이 있어야한다.
[규칙 5] 인자가 없는 옵션은 하나의 - 다음에 묶여서 올 수 있다. (-xvf)
[규칙 6] 옵션의 첫번째 인자는 공백이나 탭으로 띄고 입력해야 한다. (-l /tmp)
[규칙 7] 인자가 있어야하는 옵션에서 인자를 생략할 수 없다.
[규칙 9] 명령행에서 모든 옵션은 명령의 인자보다 앞에 와야한다. ( ls -l /tmp)
확장 규칙 : 솔라리스에서 개발된 것으로 기본 규칙과는 달리 긴 옵션을 사용할 수 있다.
[규칙 15] 긴 옵션은 -- 다음에 와야 한다. 옵션명으로는 문자나 숫자, - 만 사용할 수 있으며, -으로 연결한 1~3개 단어를 사용할 수 있다.
[규칙 16] '--이름=인자'형태는 긴 옵션의 사용에서 옵션의 인자를 상세히 지정할 때 사용한다. '--이름 인자'도 가능함.
[규칙 18] 모든 짧은 옵션에 대응하는 긴 옵션이 있어야하고, 긴 옵션에 대응하는 짧은 옵션이 있어야한다.
명령어 -a --긴 옵션1 -c 옵션 인자 -f 옵션인자 --긴 옵션2=옵션인자
--긴 옵션3 옵션 인자 파일명
<getopt함수응용: ex1_7.c>
#include <stdio.h>
int main(int argc, char *argv[]){
int n;
extern char * optarg;
extern int optind;
printf("Current Optind : %d\n", optind);
while((n=getopt(argc, argv, "abc:")) != -1) {
switch(n){
case 'a':
printf("Option : a\n");
break;
case 'b':
printf("Option : b\n");
break;
case 'c':
printf("option : c, Argument =%s\n", optarg);
break;
}
printf("Next Optind : %d\n", optind);
}
return 0;
}
- 실행시 옵션을 지정하지 않으면 특별한 작업이 없다. 정상적인 옵션을 지정하면 이를 인식하고, -c 옵션에 인자가 없거나 잘못된 옵션을 지정하면 오류메세지가 출력된다.