0. Minishell subject!
기본 보기
Search
•
안닫힌 ' 이나 " 는 핲 필요 없음, \ 이나 ; . 가 있으면 안됨
•
전역 변수 1개 만 가능
•
새로운 커맨드를 입력 받을때는 prompt 를 출력해야댐
•
History가 돼야함
•
PATH 변수나, 상대 경로, 절대 경로 에 있는걸 기반으로 올바르게 검색하고 실행해야한다.
•
구현해야할 builtin
◦
echo (n 옵션)
◦
cd (절대, 상대 경로만)
◦
pwd
◦
export
◦
unset
◦
env
◦
exit
•
리다이렉션 되야함
•
파이프 있어야함
•
환경 변수가 작동해야함
•
$? 는 가장 최근 실행된 파이프라인의 종료 값이 들어가야함
•
ctrl-C, ctrl-D, ctrl-\ 작동해야댐
◦
ctrl-C : prompt 출력
◦
ctrl-D : 쉘 종료
◦
ctrl-\ : 아무것도 안함
실행부
•
builtin 함수를 우선 구현해야 한다.(mantatory에 있는 함수들!)
파싱
•
; 없음
•
파싱해서 명령어와 실행문을 넘겨주어야한다.
1. 함수 정리하기!
이미 아는 함수
•
printf, malloc, free, write, open, read, close, exit
fork
function
fork함수를 사용하면 새로운 프로세스를 하나 호출한다.
이때, 호출하는 자식 프로세스는 부모 프로세스의 메모리를 그대로 복사하여 가진다.
그리고 fork함수 호출 이후 각자의 메모리를 사용하여 실행된다.
#include <unistd.h> //header file
pid_t fork(void);
C
복사
return value
•
성공 시 : 부모 프로세스에서는 자식 프로세스의 PID값, 자식 프로세스에서는 0
•
실패 시 : -1
example
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int x = 0;
fork();
x = 1;
printf("PID : %d, x : %d\n", getpid(), x);
return (0);
}
C
복사
$ ./a.out
PID : 8270, x : 1
PID : 8271, x : 1
Shell
복사
결국 x 에 값을 대입할 때, fork() 명령 이전에 대입하나 이후에 대입하나 상관이 없다!
fork를 하면 자식 프로세스가 부모의 메모리를 그대로 복사해서 가지기 때문.
이후 같은 작업을 각 프로세스가 개별적으로 실행한다.
또한 자식 프로세스는 fork()함수를 실행하지 않기 때문에 이때 getpid()의 return value는 0이다. 따라서 getpid()의 return value를 기준으로 자식인지 부모인지 알 수 있다.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
pid = fork();
if(pid > 0) // 부모 코드
printf("부모 프로세스 입니다.");
else // 자식 코드
printf("자식 프로세스 입니다.");
return (0);
}
C
복사
wait
function
1.
자식 프로세스가 동작 중이면 상태를 얻어올 때까지 대기
2.
wait() 함수 호출자가 시그널을 받을 때까지 대기
3.
자식 프로세스가 종료된 상태라면 즉시 호출이 반환되어 상태를 얻음, 이 때 wait() 함수는 자식 프로세스의 프로세스 ID를 반환
4.
자식 프로세스가 없다면 호출이 즉시 반환되며, 에러값을 반환
#include <sys/wait.h>
pid_t wait(int *statloc);
C
복사
wait()의 인자 status 를 통하여 자식 프로세스의 상태를 받아올 수 있는데,
return value
•
성공 시 : PID
•
실패 시 : -1
example
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pidi;
int status,i;
pid = fork();
if (pid > 0)
{
pid_t waitpid;
printf("부모 PID : %d\n", getpid());
waitpid = wait(&status); // 자식 프로세스의 상태를 받아올 때까지 wait!
if (waitpid == -1)
printf("error\n");
else
{
if (WIFEXITED(status))
printf("자식 프로세스 정상 종료\n");
else if (WIFSIGNALED(status))
printf("자식 프로세스 비정상 종료: %d\n", WTERMSIG(status));
}
}
else if(pid == 0){ // 자식 프로세스
sleep(6);
printf("자식 PID : %ld \n",(long)getpid());
}
else { // fork 실패
perror("fork Fail! \n");
return (-1);
}
return (0);
}
C
복사
$ ./a.out
부모 PID : 10695
자식 PID : 10696
자식 프로세스 정상 종료
Shell
복사
wait 명령을 사용할 때 위치에 주의하여야 한다!
만약 위 코드에서 부모 pid를 출력하는 부분이 wait명령어 아래로 내려간다면, 부모 pid출력이 자식프로세스가 종료될때까지 기다렸다가 출력하게 된다.
wait()관련 함수에서 자식 프로세스의 종료 상태를 확인하기 위해서 인수로 전달했던 변수 status 값은 아래와 같이 구성되어 있다! 기존에는 255를 기준으로 비교 했었지만 아래 매크로를 활용해서 간단하게 확인할 수 있다.
기본 보기
Search
WIF로 시작하는 macro는 상위 바이트의 상태를 판단하는 함수이며 나머지 macro함수는 상세 값을 읽을 수 있습니다.
이제 자식 프로세스를 오랜 시간동안 실행시키고 터미널에서 kill명령으로 자식 프로세스를 종료시켜보자!
$ kill -9 13439
부모 PID : 13438, 자식 PID : 13439
자식 프로세스 비정상 종료: 9
Shell
복사
waitpid
function
waitpid()는 wait()함수와 동일하게 자식 프로세스를 기다릴 때 사용한다. 하지만 자식 프로세스가 종료될 때까지 차단되는 것을 원하지 않을 경우, 옵션을 사용하여 차단을 방지할 수 있다.
#include <sys/wait.h> //header file
pid_t waitpid(pid_t pid, int *status, int options);
C
복사
•
pid : wait()할 자식 프로세스의 유형
◦
pid < -1 : 그룹ID가 절대값과 같은 자식 프로세스를 기다린다
◦
pid == -1 : 아무 자식 프로세스 ID라도 기다린다
◦
pid == 0 : 자신과 같은 프로세스 그룹 ID를 가진 자식 프로세스를 기다린다.
◦
pid > 0 : 인자로 넘어온 pid를 가진 자식 프로세스만 기다린다.
•
status : wait()함수와 동일
•
options : 0 혹은 상수의 조합으로 설정된다
◦
0 : 결과를 return 할 떄까지 block한다
◦
WNOHANG : 현재 종료된 자식 프로세스가 없으면 block하지 않고 바로 0을 반환한다
◦
WUNTRACED : 자식 프로세스가 STOP하면 반환한다
◦
WCONTINUED : STOP되었던 자식 프로세스가 재 실행되면 반환한다
return value
•
성공 시 : PID → 상태가 변경된 자식 프로세스 ID (status가 상태값 저장)
•
성공 시 : 0 → option이 WNUHANG인 경우 종료된 자식 프로세스가 없으면 0을 return
•
실패 시 : -1 → wait 중 오류가 발생, 오류 내용은 errno 전역변수에 설정
example
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid;
int status,i;
pid = fork();
if (pid > 0)
{
pid_t waitpid;
printf("부모 PID : %d, 자식 PID : %d\n", getpid(), pid);
}
else if(pid == 0){ // 자식 프로세스
for (int i = 0 ; i < 3 ; ++i)
sleep(1);
printf("자식 PID : %ld \n",(long)getpid());
printf("자식 종료\n");
}
else { // fork 실패
perror("fork Fail! \n");
return -1;
}
pid = waitpid(pid, &status, 0);
if (pid == -1 )
{
printf("error\n");
}
else
{
if (WIFEXITED(status)){
printf("프로그램에서 exited(%d) 또는 main에서 return ;하여 종료되었습니다.\n",
WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("siganl %d번이 발생하여 종료되었습니다.\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("signal %d번으로 인하여 stop되었습니다. \n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("stop된 프로세스를 진행합니다\n");
}
}
return 0;
}
C
복사
wait3, wait4
function
wait3, wait4 함수는 사용자 시간 정보를 확인할 수 있다.
#include <sys/types.h> //header file
#include <sys/wait.h>
pid_t wait3(int *staloc, int options, struct rusage *rus);
pid_t wait4(pid_t pid, int *staloc, int options, struct rusage *rus);
C
복사
parameters
•
staloc, options, pid : 위와 동일
•
rusage : 자식 프로세스의 리소스 사용량에 대한 정보가 담긴다. (struct rusage 형태로 담긴다)
return value
•
성공 시 : PID, 만약 함수가 WNOHANG 옵션으로 실행되었고, 자식 프로세스가 아직 종료되지 않았을 때, 0
•
실패 시 : -1
example
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
void ViewRUsage(pid_t pid, struct rusage *pru);
int main()
{
pid_t cpid = fork();
if(cpid == -1)
{
perror("error fork");
return 0;
}
if(cpid>0)
{
printf("<parent> fork child pid:%u\n",cpid);
int rvalue = 0;
struct rusage ru;
pid_t wpid = wait3(&rvalue,0, &ru);
ViewRUsage(wpid, &ru);
}
else
{
printf("<child> pid:%d \n",getpid());
int i=0,j=0;
for(i=0;i<100000;i++)
{
fprintf(stderr,".");
}
}
return 0;
}
void ViewRUsage(pid_t pid, struct rusage *pru)
{
printf("\n=== pid rusage info ===\n");
struct timeval *tv = &(pru->ru_utime);
printf("user CPU time used [%ld]sec [%d]usec\n", tv->tv_sec,tv->tv_usec );
tv = &(pru->ru_stime);
printf("system CPU time used [%ld]sec [%d]usec\n", tv->tv_sec,tv->tv_usec );
}
C
복사
signal
프로세스가 시그널을 받게 되면
1. 시그널에 해당되는 기본 동작을 하거나
2. 그 시그널을 무시하거나
3. 사용자가 정의한 함수를 통해 동작 방식을 바꿀 수 있다.
function
위와 같은 시그널을 제어할 수 있는 함수. signal번호를 받아와 해당 signal에서의 행동을 지정할 수 있다.
#include <signal.h> //header file
void (*signal(int signum, void (*handler)(int)))(int);
C
복사
parameters
•
signum : 시그널 번호
•
(*handler)(int) : 시그널을 처리할 핸들러
return value
•
성공 시 : void *()(int); 이전에 설정된 시그널 핸들러
•
실패 시 : null(?)
아래는 MacOS에 정의되어 있는 Signal들이다.
•
SIGKILL, SIGSTOP 등은 제어할 수 없다.
example
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void (*old_fun)(int);
void sigint_handler(int signo)
{
printf("signo : %d", signo);
printf("Ctrl-C 키를 누르셨죠!!\n");
printf("또 누르시면 종료됩니다.\n");
signal(SIGINT, old_fun);
//signal( SIGINT, SIG_DFL);
}
int main( void)
{
old_fun = signal(SIGINT, sigint_handler);
// printf("asdf : %d", SIGTSTP);
// printf("zxcv : %d", SIGCHLD);
while (1)
{
printf("forum.falinux.com\n");
sleep(1);
}
}
C
복사
kill
function
프로세스에 시그널을 전송해주는 함수. 시그널 SIGKILL을 보내면 쉘의 kill과 같은 역할을 한다.
#include <signal.h> //header file
int kill(pid_t pid, int signo)
C
복사
parameters
•
pid, signo : 위와 동일
return value
•
성공 시 : 0
•
실패 시 : -1
getcwd
function
현재 작업 중인 디렉토리를 가져온다
#include <unistd.h> //header file
char *getcwd(char *buf, size_t size);
C
복사
parameters
•
buf : 현재 작업 디렉토리를 저장할 buffer. 만약 buffer가 null이면 malloc을 통해서 할당된 메모리를 사용한다. 따라서 이 경우 무조건 free를 해주어야 한다.
•
size : buffer에 할당된 메모리의 크기
return value
•
성공 시 : 포인터
•
실패 시 : null (오류 내용은 errno에 저장된다)
example
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
int main() {
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("Current working dir: %s\n", cwd);
} else {
perror("getcwd() error");
return 1;
}
return 0;
}
C
복사
chdir
function
작업 디렉토리 폴더 변경하기 (cd in linux)
// man 2 chdir
#include <unistd.h> //header file
int chdir(const char *dirname);
C
복사
return value
•
성공 시 : 0
•
실패 시 : -1
example
#include <stdio.h>
#include <limits.h>
#include <unistd.h> // chdir header
int main(void)
{
char buffer[PATH_MAX] = { 0, };
char changeDir[PATH_MAX] = { "/Users/42seoul/minishell/" };
int result = chdir(changeDir);
if(result == 0)
printf("Success\n");
else
perror("Fail...\n");
return 0;
}
C
복사
stat
function
파일의 크기, 권한, 생성일시, 최종 변경일 등 파일의 상태나 정보를 얻는 함수이다.
stat(2) 함수는 symbolic link인 파일을 path로 넘기면 그 원본 파일의 정보를 얻는다.
// man 2 stat
#include <sys/stat.h> //header file
int stat(const char *path, struct stat *buf);
C
복사
parameters
•
path : 파일 명 또는 파일에 대한 상대경로/절대경로
•
buf : 파일의 상태 및 정보를 저장할 구조체
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
time_t st_atime;
tiem_t st_mtime;
time_t st_ctime;
};
C
복사
return value
•
성공 시 : 0
•
실패 시 : -1
example
상세 예시는 아래 블로그를 가면 확인할 수 있다.
lstat, fstat
#include <unistd.h>
int lstat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
C
복사
•
lstat : symbolic link인 파일 자체의 정보를 얻는다. 나머지는 같다.
•
fstat : 인자로 가져온 fd(열려있는 file)의 정보를 얻어온다. 나머지는 같다.
execve
function
실행가능한 파일인 filename의 실행 코드를 현재 프로세스에 적재하여 기존의 실행 코드와 교체하여 새로운 기능으로 실행한다. 즉, 현재 실행되는 프로그램의 기능은 없어지고 filename 프로그램을 메모리에 Loading하여 처음부터 실행한다.
#include <unistd.h> //header file
int execve(const char *filename, char *const argv[], char *const envp[]);
C
복사
parameters
•
filename : 교체할 실행 파일 / 명령어. path와 명령어가 합쳐진 형태라고 생각하면 편함
ex) "usr/bin/ls"
•
argv : execve에는 argc가 없으므로 array의 마지막 원소 다음은 NULL이 있다
•
envp : key = value 형태의 환경변수 문자열 배열 리스트. 마지막은 NULL. 만약 이미 설정된 환경변수를 사용하려면 environ 전역변수를 그냥 사용한다.
return value
•
성공 시 : 없음 (이미 지정된 프로그램의 로직으로 실행되기 때문에 return을 받을 수 없다)
•
실패 시 : -1
명령어 위치를 찾아보자
which "명령어"
→ 만약 alias가 되어 있으면 해제하고 확인 해야 한다.
example
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
extern char **environ;
int main(int argc, char *argv[], char **envp)
{
char **new_argv;
char command[] = "ls";
int idx;
new_argv = malloc(sizeof(char *) * argc + 1);
// 명령어를 ls로 변경
new_argv[0] = command;
// command line으로 넘어온 parameter를 그대로 사용
for (idx = 1 ; idx < argc ; ++idx)
new_argv[idx] = argv[idx];
// argc를 execve 파라미터에 전달할 수 없기 때문에 NULL을 끝으로 지정해우저야 함
new_argv[argc] = NULL;
if (execve("/bin/ls", new_argv, environ) == -1){
fprintf(stderr, "프로그램 실행 error: %s\n", strerror(errno));
return 1;
}
printf("이후 로직은 실행되지 않습니다..\n");
return (0);
}
C
복사
dup
function
파일 디스크립터를 복제하여 다른 파일 디스크립터 생성
#include <unistd.h> //header file
int dup(int file_des);
C
복사
parameters
•
file_des : 파일 디스크립터
return value
•
성공 시 : 파일 디스크립터
•
실패 시 : -1
example
#include <unistd.h> // dup header file
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd1, fd2;
if ((fd1 = open("file_1.txt", O_RDONLY)) < 0)
{
printf("file open error\n");
exit(0);
}
fd2 = dup(fd1);
printf("fd1 : %d, fd2 : %d\n", fd1, fd2);
close(fd1);
close(fd2);
return (0);
}
C
복사
•
항상 낮은 서술자를 반환함
dup2
function
fd2 에 기존의 파일 디스크립터를 복제.
만일 fd2가 이미 열려있으면 fd2를 닫은 후 복제.
#include <unistd.h> //header file
int dup2(int file_des1, int file_des2);
C
복사
parameters
•
file_des : 기존의 파일 디스크립터
•
file_des2 : 새로운 파일 디스크립터
return value
•
성공 시 : -1 이외의 값
•
실패 시 : -1
example
int main(void)
{
int fd;
if ((fd = open("file_1.txt", O_RDONLY)) < 0){
printf("file open error\n");
exit(0);
}
+- /* 표준 출력을 file_1.txt 파일로 redirection 함 */
dup2(fd, 1);
/* 표준 오류를 file_1.txt 파일로 redirection 함 */
dup2(fd, 2);
close(fd);
return (1);
}
C
복사
pipe
function
서로 독립된 프로세스들이 데이터를 주고 받을 수 있게 도와준다.
#include <unistd.h> //header file
int pipe(int fd[2]);
C
복사
parameters
•
fd[0] : 함수 호출 후 fd[0]에 데이터를 입력 받을 수 있는 fd가 담김(파이프 출구)
•
fd[1] : 함수 호출 후 fd[1]에 데이터를 출력할 수 있는 fd가 담김(파이프 입구)
return value
•
성공 시 : 0
•
실패 시 : -1
example
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int pipes[2] ;
void parent_proc() {
char * buf = 0x0;
ssize_t s;
size_t len = 0;
// 읽기용 파이프를 닫는다
close(pipes[0]);
while ((s = getline(&buf, &len, stdin)) != -1) {
buf[s - 1] = 0x0;
ssize_t sent = 0;
char * data = buf;
while (sent < s) {
sent += write(pipes[1], buf + sent, s - sent);
}
free(buf);
buf = 0x0;
len = 0;
}
close(pipes[1]);
}
void child_proc() {
char buf[32];
ssize_t s;
// 쓰기용 파이프를 닫는다
close(pipes[1]);
while ((s = read(pipes[0], buf, 31)) > 0) {
buf[s + 1] = 0x0;
printf(">%s\n", buf);
}
exit(0);
}
int main() {
pid_t child_pid;
int exit_code;
if (pipe(pipes) != 0) {
perror("Error");
exit(1);
}
printf("%d %d\n", pipes[0], pipes[1]);
child_pid = fork();
if (child_pid == 0)
child_proc();
else
parent_proc();
return (0);
}
C
복사
opendir
function
디렉토리 열기
#include <dirent.h> // header file
DIR * opendir(const char * name);
C
복사
parameters
•
name : open 할 디렉토리의 이름
return value
•
성공 시 : DIR 포인터 디렉토리 정보 구조체 포인터
•
실패 시 : NULL
readdir
function
디렉토리 내에 있는 모든 파일과 디렉토리 정보 구하기
#include <dirent.h> // header file
struct dirent *readdir(DIR *dirp);
C
복사
parameters
•
dirp : open 할때 반환되는 DIR 포인터
return value
•
성공 시 : 디렉토리내의 파일/디렉토리에 대한 정보를 가진 구조체 포인터
•
실패 시 : NULL
•
readdir()을 처음 호출하면 opendir()를 통해 연 디렉토리 내의 첫번째 파일에 대한 정보를 가져오고, 다시 호출시 두번째 파일에 대한 정보, 다시 호출시 세번째 파일을 호출,,, 하다가 더이상 파일이나 디렉토리가 없으면 NULL 반환
closedir
function
디렉토리 닫기
#include <dirent.h> // header file
int closedir(DIR *dirp);
C
복사
parameters
•
dirp : open 할때 반환되는 DIR 포인터
return value
•
성공 시 : 0
•
실패 시 : -1
example (opendir/readdir/closedir)
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
int main()
{
DIR *dir_info;
struct dirent *dir_entry;
mkdir("test_A", 0755); // 실행파일이 있는 곳에 dir 생성
mkdir("test_B", 0755);
dir_info = opendir("."); // 현재 디렉토리 열기
if (dir_info)
{
while((dir_entry = readdir(dir_info))) // 디렉토리 안에 있는 모든 파일과 디렉토리 출력
printf("%s\n", dir_entry->d_name); // d_name : 읽힌 디렉토리/파일의 이름 저장
closedir(dir_info);
}
return (0);
}
C
복사
strerror
function
시스템 오류 번호에 대한 오류 메세지를 문자열로 반환하는 함수이다.
#include <string.h>
char *strerror(int errnum);
C
복사
parameters
•
errnum : 오류 번호
return value
•
성공 시 : 오류 번호와 일치하는 오류 메세지 문자열
•
실패 시 : NULL or "Unknown error nnn"
example
#include <errno.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *fp;
if ((fp = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "errno[%d] : %s\n", errno, strerror(errno));
return (1);
}
return (0);
}
C
복사
errno
마지막으로 발생한 에러 번호
#include <errno.h>
extern int errno;
C
복사
isatty
function
매개변수로 넣은
#include <unistd.h>
int isatty(int fildes);
C
복사
parameters
•
fildes : fd, 파일디스크립터
return value
•
성공 시 : 1 (터미널에 연결되어 있는 경우)
•
실패 시 : 0
example
코드 실행 전 현재 pc에 어떤 tty파일들이 있는지 확인해보자
$ cd /dev
$ ls
C
복사
tty(teletypewriter)
리눅스 디바이스 드라이브 중에서 콘솔이나 터미널을 의미
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd;
printf("%d\n", isatty(0));
fd = open("/dev/ttyp0",O_RDONLY);
printf("fd : %d, %d\n", fd, isatty(fd));
return (0);
}
C
복사
ttyname
function
fd에 대한 터미널 이름을 얻어온다.
#include <unistd.h>
char *ttyname(int desc);
C
복사
parameters
•
desc : fd
return value
•
성공 시 : 터미널 이름, 없으면 "(null)"
•
실패 시 : NULL
example
#include <unistd.h>
#include <stdio.h>
int main(void)
{
printf("your tty name is : %s\n", ttyname(0));
printf("your tty name is : %s\n", ttyname(1));
printf("your tty name is : %s\n", ttyname(2));
return (0);
}
C
복사
➜ funcStudy git:(main) ✗ ./a.out
your tty name is : /dev/ttys008
your tty name is : /dev/ttys008
your tty name is : /dev/ttys008
Shell
복사
ttyslot
function
ttyslot - find the slot of the current user's terminal in somefile
#include <unistd.h>
int ttyslot(void);
C
복사
return value
•
성공 시 : slot number
•
실패 시 : 0, -1
example
C
복사
•
ioctl
•
getenv
•
tcsetattr
•
tcgetattr
tgetent
function
커서 제어를 위해서는 termcap 라이브러리를 사용해야 한다.
라이브러리 사용을 위한 세팅은 tgetent() 함수로 시작된다.
termcap 라이브러리를 사용할 경우 컴파일 시 -lncurses 옵션을 붙여주어야 한다.
#include <curses.h>
#include <term.h>
int tgetent(char *bp, const char *name);
C
복사
parameters
•
bp : 버퍼 포인터
•
name : 루틴이름(?)
return value
•
성공 시 : 1
•
해당항목이 없을 경우 : 0
•
terminfo 데이터베이스를 찾을 수 없는 경우 : -1
example
#include <termcap.h>
char *env = getenv("TERM"); //TERM 설정을 가져옴
if (env == NULL)
env = "xterm"; //대부분 기본값은 xterm
tgetent(NULL, env); // xterm 설정을 사용하도록 초기화
char *cm = tgetstr("cm", NULL); // cursor motion
char *ce = tgetstr("ce", NULL); // 현재 커서 위치에서 한 줄의 끝까지 지우기
C
복사
tgetflag
function
??
#include <curses.h>
int tgetflag(char id[2]);
C
복사
parameters
•
id : ??
return value
•
성공 시 : the boolean entry for id
•
실패 시 : 0
tgetnum
function
??
#include <curses.h>
int tgetnum(char id[2]);
C
복사
parameters
•
id : ??
return value
•
성공 시 : the numeric entry for id
•
실패 시 : -1
tgetstr
function
사용할 수 있는 루틴을 가져옴
#include <curses.h>
char *tgetstr(char id[2], char **area);
C
복사
parameters
•
id : ??
•
area : ??
return value
•
성공 시 : the string entry for id
•
실패 시 : 0
tgoto
function
동작 실행에 필요한 명령을 받기
#include <curses.h>
char *tgoto(char *cap,int col,int row);
C
복사
parameters
•
cap : 명령어
•
col : 이동할 행
•
row : 이동할 열
return value
•
성공 시 : ??
•
실패 시 : ??
example
// (5, 5) 위치로 커서를 옮기기
// 터미널 창의 가장 왼쪽 위가 (0, 0)
#include <unistd.h>
#include <termcap.h>
int putchar_tc(int tc)
{
write(1, &tc, 1);
return (0);
}
int main(void)
{
tgetent(NULL, "xterm");
char *cm = tgetstr("cm", NULL);
tputs(tgoto(cm, 5, 5), 1, putchar_tc);
// (5, 5) 위치로 이동하는(cm - cursor motion) 명령을 tputs에 전달하여 실행
}
// ce 명령의 경우 tgoto 없이 바로 tputs(ce, 1, putchar_tc)의 형식으로 사용해주면 된다.
// 예시 : tputs에 있음
C
복사
tputs
function
동작 실행 하기
#include <curses.h>
int tputs(const char *str, int affcnt, int (*putc)(int));
C
복사
parameters
•
str : ??
•
affcnt : ??
•
putc : ??
return value
•
성공 시 : ??
•
실패 시 : ??
example
// ce - clear line from cursor 명령
#include <unistd.h>
#include <termcap.h>
int putchar_tc(int tc)
{
write(1, &tc, 1);
return (0);
}
int main(void)
{
tgetent(NULL, "xterm");
char *cm = tgetstr("cm", NULL);
tputs(ce, 1, putchar_tc);
}
C
복사
2. 명령어 정리하기!
echo (-n 옵션)
•
C언어에서의 printf 와 같은 역할을 함.
1) 옵션 없이 → 에코 후 개행출력
→ \ 를 만나도 특별하게 해석하지 않고 문자 그대로 출력
2) -n 옵션 → 에코 후 개행하지 않음
testcase → 무조건 돌려볼 것...
echo
echo hello
echo -n hello
echo hello -n
echo -nnn hello
echo -n-n hello
echo -nnn hello -n
echo -nnn -n hello
echo -
echo - -
echo --
echo -n -n -nhjk hello
echo -n -n -n -n -n hello
echo "hello World"
echo "hello World"
echo \\\"\'''\"
Plain Text
복사
cd (상대경로 또는 절대경로만)
•
"change directory"의 약자로 특정 디렉토리로 이동하고 싶을 때 사용.
cd 뒤에 가고 싶은 디렉토리 경로를 입력.
cd / : 루트 디렉토리로 이동 (절대 경로)
cd /home/pi : /home/pi 로 이동 (상대 경로)
pwd (옵션 없이)
•
"print working directory"의 약자로 현재 작업 중인 디렉토리의 절대 경로를 반환
export (옵션 없이)
•
사용자 환경 변수를 전역 변수로 설정 (변수명에 공백이 있으면 안됨)
# 예시
export <변수명>=<값> : export JAVA_HOME=/user/lib/java-7-openjdk-amd64/
Shell
복사
# 짜증나는 예시
export a #key값만 생성
export b= #value에 아무 값 없음
export c=hello
export c+=world #환경변수 뒤에 덧붙이기
export d="oh my god" #echo출력과 export출력 다름
export e=elephant f=flower
Bash
복사
echo로 출력
(매개변수 없는 export) 출력결과
unset (옵션 없이)
•
변수를 제거
# 예시
[root@wiki ~] str="hello world"
[root@wiki ~] echo $str
hello world
[root@wiki ~] unset str
[root@wiki ~] echo $str
[root@zetawiki ~]
Shell
복사
env (옵션과 매개변수 없이)
•
전역 변수 설정 및 조회
exit (옵션 없이)
•
shell 종료
', " (따옴표)
<, >, >> (리디렉션)
- file descriptor aggregation을 제외하고 bash에서처럼 작동
•
< : 입력 리다이렉션
•
> : 출력 리다이렉션
- 출력된 파일은 존재하지 않을 경우 자동생성
- 만약 이미 존재하는 경우 덮어쓰기
•
>> : > 와 같지만 이미 파일이 존재하는 경우 데이터를 추가한다
<<
•
연산자의 오른쪽에 지정된 것이 한 줄 (예 : EOF)에서 충족 될 때까지 줄 바꿈을 포함한 사용자 입력을 가져옵니다.
•
EOF 값을 제외하고 읽은 모든 것을 왼쪽 프로그램의 표준 입력으로 보냅니다.
cat << EOF
> Hello
> World
> EOF
--result--
Hello
World
Shell
복사
| (파이프)
•
command1 | command2 와 같은 형태로 사용되고, command1의 표준 출력을 command2의 표준 입력으로 전달. (&를 붙이면 표준 에러도 함께 전달)