#.head 명령어 실습 1
*처리 대상은 표준 입력으로만한다. 즉, 실행인자로 파일 이름을 받는 기능은 생략한다.
*출력할 줄의 수는 첫 번째 실행 인자로 전달 받는다.
예제
//처리 대상은 표준 입력으로만한다. 즉, 실행인자로 파일 이름을 받는 기능은 생략한다. | |
//출력할 줄의 수는 첫 번째 실행 인자로 전달 받는다. | |
#include <stdio.h> | |
#include <stdlib.h> | |
static void do_head(FILE *f, long nlines); | |
int main(int argc, char *argv[]){ | |
if (argc != 2 ) { | |
fprintf(stderr, "usage: %s n \n" , argv[0]); | |
exit(1); | |
} | |
printf("main 함수 표준파일 입력 -- \n"); | |
//표준파일 입력, atol: 문자를 long 타입의 숫자로 변환하는 함수 | |
//터미널에서 문자입력을 받는다. | |
do_head(stdin, atol(argv[1])); | |
exit(0); | |
} | |
static void do_head(FILE *f , long nlines){ | |
int c; | |
if (nlines < 0) { | |
return; | |
} | |
//getc 함수는 버퍼를 만들어서 넘길 필요가 없기때문에 사용하기 편리하다. | |
//fgetc를 편하게 사용하려면 한 줄의 길이를 제한할 필요가 있다. | |
while ((c= getc(f)) != EOF) { | |
//printf("long : %lu \n" , nlines); | |
//printf("c : %d \n" , c); | |
/* | |
위 printf 문 출력 내용 | |
getc의 리턴값은 문자를 정수로 변환한 값을 1바이트씩 리턴한다. | |
aa | |
long : 2 | |
c : 97 | |
along : 2 | |
c : 97 | |
along : 2 | |
c : 10 | |
bb | |
long : 1 | |
c : 98 | |
blong : 1 | |
c : 98 | |
blong : 1 | |
c : 10 | |
*/ | |
//putchar 함수로 표준 출력으로 처리 - 터미널에 입력한 내용을 그대로 쓴다. | |
if (putchar(c) < 0) { | |
exit(1); | |
} | |
//줄바꿈을 처리 | |
if (c == '\n') { | |
nlines--; | |
} | |
//nlines 가 0이면 함수 중단 | |
if (nlines == 0 ) { | |
return; | |
} | |
} | |
} |
결과

#.head 명령어 실습 2
*파일의 경로를 실행 인자로 받아들이는 기능을 구현
*첫번째 인자는 이전처럼 출력할 라인 수, 두번째 이후 인자를 파일이름으로 간주한다.
예제
//파일의 경로를 실행 인자로 받아들이는 기능을 구현 | |
//첫번째 인자는 이전처럼 출력할 라인 수, 두번째 이후 인자를 파일이름으로 간주한다. | |
#include <stdio.h> | |
#include <stdlib.h> | |
static void do_head(FILE *f, long nlines); | |
int main(int argc, char *argv[]){ | |
long nlines; | |
//명령어 : /head 5 abc.txt def.txt | |
//파일을 지정하지 않았으면 오류발생 | |
if (argc < 2 ) { | |
fprintf(stderr, "usage: %s n \n" , argv[0]); | |
exit(1); | |
} | |
printf("main 함수 표준파일 입력 -- \n"); | |
//표준파일 입력, atol: 문자를 long 타입의 숫자로 변환하는 함수 | |
//터미널에서 문자입력을 받는다. | |
//터미널에서 인자로 받은 줄 수 | |
nlines = atol(argv[1]); | |
//터미널에서 줄수, 까지 입력받았다면 표준 입출력 함수 실행 | |
if (argc == 2) { | |
do_head(stdin, nlines); | |
} | |
else{ //*** 이부분 추가 **** | |
int i; | |
for (i = 2; i < argc; i++) { | |
FILE *f; | |
//파일을 읽기 전용으로 열기 | |
f = fopen(argv[i], "r"); | |
if (!f) { | |
perror(argv[i]); | |
exit(1); | |
} | |
//출력할 파일과 출력라인 값을 전달. | |
do_head(f,nlines); | |
//파일 닫기 | |
fclose(f); | |
}//for - end | |
}//else end | |
exit(0); | |
} | |
static void do_head(FILE *f , long nlines){ | |
int c; | |
if (nlines < 0) { | |
return; | |
} | |
//getc 함수는 버퍼를 만들어서 넘길 필요가 없기때문에 사용하기 편리하다. | |
//fgetc를 편하게 사용하려면 한 줄의 길이를 제한할 필요가 있다. | |
while ((c= getc(f)) != EOF) { | |
//printf("long : %lu \n" , nlines); | |
//printf("c : %d \n" , c); | |
/* | |
위 printf 문 출력 내용 | |
getc의 리턴값은 문자를 정수로 변환한 값을 1바이트씩 리턴한다. | |
aa | |
long : 2 | |
c : 97 | |
along : 2 | |
c : 97 | |
along : 2 | |
c : 10 | |
bb | |
long : 1 | |
c : 98 | |
blong : 1 | |
c : 98 | |
blong : 1 | |
c : 10 | |
*/ | |
//putchar 함수로 표준 출력으로 처리 - 터미널에 입력한 내용을 그대로 쓴다. | |
if (putchar(c) < 0) { | |
exit(1); | |
} | |
//줄바꿈을 처리 | |
if (c == '\n') { | |
nlines--; | |
} | |
//nlines 가 0이면 함수 중단 | |
if (nlines == 0 ) { | |
return; | |
} | |
} | |
} |
결과

#.head 명령어 실습 2 -2
*파일의 경로를 실행 인자로 받아들이는 기능을 구현
*첫번째 인자는 이전처럼 출력할 라인 수, 두번째 이후 인자를 파일이름으로 간주한다.
예제2-2
#include <stdio.h> | |
#include <stdlib.h> | |
static void do_head(FILE *f, long nlines); | |
int main(int argc, char *argv[]){ | |
FILE *readFile; | |
//오직 실행파일명 + 줄수 + 파일명 | |
if (argc < 2) { | |
fprintf(stderr, "usage: %s 예)실행파일명 + 줄수 + 파일명 \n" , argv[0]); | |
exit(1); | |
} | |
//파일을 읽기 전용으로 열기 | |
readFile = fopen(argv[2] , "r"); | |
//NULL 이면 파일 읽기 실패 | |
if (readFile == NULL) { | |
fprintf(stderr, "usage: %s 파일 열기 실패 \n" , argv[2]); | |
exit(1); | |
} | |
//표준파일 입력, atol: 문자를 long 타입의 숫자로 변환하는 함수 | |
//터미널에서 문자입력을 받는다. | |
do_head(readFile , atol(argv[1])); | |
//파일 닫기 | |
fclose(readFile); | |
exit(0); | |
} | |
static void do_head(FILE *f, long nlines){ | |
printf("file : %p \n" , f); | |
printf("nlines : %ld \n" , nlines); | |
//줄 수가 0 보다 작으면 리턴 | |
if (nlines < 0) { | |
fprintf(stderr, "usage: %s \n" , "줄 수를 입력해주세요"); | |
exit(1); | |
} | |
/* | |
- getc | |
- 설명 | |
스트림에서 한 문자를 읽어온다. | |
문자를 읽어온 스트림의 내부 파일 위치 표시자가 현재 가리키는 문자를 리턴한다. | |
그리고 내부 파일 표시자는 그 다음 문자를 가리키게 된다. | |
- 인자 | |
문자를 읽어올 스트림의 FILE 객체를 가리키는 포인터 | |
- 리턴값 | |
읽어들인 문자는 int 값으로 리턴된다.만일 파일 끝에 도달하거나, 읽기 오류가 발생한다면 함수는 EOF 를 리턴하고 이에 대응하는 오류 혹은 EOF 표시자가 설정된다. 여러분은 ferror이나 feof함수를 통해 각각 어떤 오류가 발생했는지, 파일 끝에 도달하였는지 알 수 있다. | |
*/ | |
for (; ; ) { | |
//printf("start!\n"); | |
int c = getc(f); | |
//printf("c : %d \n" , c); | |
//결과 : 문자 a를 입력하고 엔터치면 97 과 10 출력한다. | |
//getc의 리턴값은 문자를 정수로 변환한 값을 1바이트씩 리턴한다. | |
//문자의 마지막을 만났을때 | |
if (c == EOF) { | |
break; | |
} | |
//엔터문자(줄바꿈) 만나면 nlines 변수 값 -1 | |
if (c == '\n') { | |
nlines--; | |
} | |
//커멘드 라인에서 입력한 줄수를 다 출력하면 빠져나온다. | |
if (nlines == 0) { | |
break; | |
} | |
//출력하기 | |
int p = putchar(c); | |
//printf("p : %d \n" , p); | |
//출력한 1byte 정수값을 리턴함 | |
//오류처리 | |
if (p < 0) { | |
exit(1); | |
} | |
} // for - end | |
printf("\n"); | |
} |
#.head 명령어 실습 3
*위에서 작성중인 head 명령어 소스에 getopt_long()을 사용해서
*옵션을 처리하는 기능을 추가하는 기능.
예제
//위에서 작성중인 head 명령어 소스에 getopt_long()을 사용해서 | |
//옵션을 처리하는 기능을 추가하는 기능. | |
/* | |
출력할 줄 수를 지정하는 -n | |
동일한 의미의 롱 옵션 --lines | |
간단한 헬프 메시지를 표시하는 --help | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
// [1] : getopt_long 함수를 사용하기 위해 상수를 정의하고, getopt를 include 한다. | |
#define _GNU_SOURCE | |
#include <getopt.h> | |
static void do_head(FILE *f, long nlines); | |
extern char *optarg; //현재 처리중인 옵션의 파리미터 | |
extern int optind, //현재 처리중인 옵션의 argv 인덱스 | |
opterr, //이값이 참이면 getopt가 에러 메시지를 표시 | |
optopt; //현재 처리 중인 옵션 문자 | |
#define DEFAULT_N_LINES 10 | |
// [2] : 긴옵션을 정의하기 위해 struct 옵션의 배열을 만들고 각 긴 옵션에 해당하는 요소를 정의하였다. | |
//배열의 마지막에는 모든 멤버를 0으로 대입한 요소를 넣어야 한다. | |
//required_argument : 반드시 파리미터를 취함, no_argument: 파리미터를 취하지 않음 | |
//세번째 인자에 null을 입력하면 네번재 인자의 값이 반환된다. | |
static struct option longopts[] ={ | |
{"lines" , required_argument, NULL, 'n'}, | |
{"help" , no_argument, NULL, 'h'}, | |
{0, 0, 0, 0} | |
}; | |
int main(int argc, char *argv[]){ | |
int opt; | |
long nlines = DEFAULT_N_LINES; | |
//[3] :getopt_long : 커멘드 라인 옵션을 해석하는 api | |
//항상 루프와 사용하고 호출될때마다 인자로 넘겨진 다음 옵션 문자를 반환한다. | |
//잘못된경우 ? 를 반환한다. 인자로 넘겨진 모든 옵션을 반환했으면 -1을 반환한다. | |
while((opt = getopt_long(argc,argv, "n:" , longopts , NULL)) != -1){ | |
switch(opt){ | |
// -n 옵션과 --lines 옵션을 처리한다. 옵션의 파라미터값은 optarg에 들어 있어 | |
// 여기서 출력할 줄 수를 얻는다. | |
case 'n' : | |
nlines = atol(optarg); | |
break; | |
case 'h' : | |
//명령어 사용법 출력 | |
fprintf(stdout, "usage : %s [-n LINES] [FILE...] \n " ,argv[0]); | |
exit(0); | |
break; | |
case '?' : | |
//명령어 사용법 출력 | |
fprintf(stdout, "usage : %s [-n LINES] [FILE...] \n " ,argv[0]); | |
exit(1); | |
break; | |
} | |
} | |
//[7] : getopt_long에 의한 파싱이 끝난 시점에서 optind가 argc와 같다는 것은 | |
// 옵션 이외에 추가적인 인자를 지정하지 않았음을 의미한다. | |
//optind는 getopt()나 getopt_long이 마지막으로 처리한 인자의 인덱스를 가지고 있기 때문이다. | |
//옵션 이외에 대상 파일을 지정하지 않은경우, 표준 입력에서 읽도록 했다. | |
if(optind == argc){ | |
do_head(stdin, nlines); | |
}else{ | |
int i; | |
//[8] | |
for (i = optind ; i < argc; i++) { | |
FILE *f; | |
//파일을 읽기 전용으로 열기 | |
f = fopen(argv[i], "r"); | |
if (!f) { | |
perror(argv[i]); | |
exit(1); | |
} | |
//출력할 파일과 출력라인 값을 전달. | |
do_head(f,nlines); | |
//파일 닫기 | |
fclose(f); | |
}//for - end | |
} | |
exit(0); | |
} | |
static void do_head(FILE *f , long nlines){ | |
int c; | |
if (nlines < 0) { | |
return; | |
} | |
//getc 함수는 버퍼를 만들어서 넘길 필요가 없기때문에 사용하기 편리하다. | |
//fgetc를 편하게 사용하려면 한 줄의 길이를 제한할 필요가 있다. | |
while ((c= getc(f)) != EOF) { | |
//putchar 함수로 표준 출력으로 처리 - 터미널에 입력한 내용을 그대로 쓴다. | |
if (putchar(c) < 0) { | |
exit(1); | |
} | |
//줄바꿈을 처리 | |
if (c == '\n') { | |
nlines--; | |
} | |
//nlines 가 0이면 함수 중단 | |
if (nlines == 0 ) { | |
return; | |
} | |
} | |
} |
결과

#.head 명령어 실습 3-2
*위에서 작성중인 head 명령어 소스에 getopt_long()을 사용해서
*옵션을 처리하는 기능을 추가하는 기능.
예제 3-2
//위에서 작성중인 head 명령어 소스에 getopt_long()을 사용해서 | |
//옵션을 처리하는 기능을 추가하는 기능. | |
/* | |
출력할 줄 수를 지정하는 -n | |
동일한 의미의 롱 옵션 --lines | |
간단한 헬프 메시지를 표시하는 --help | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#define _GUN_SOURCE | |
#include <getopt.h> | |
static void do_head(FILE *f, long nlines); | |
extern char *optarg; //현재 처리중인 옵션의 파리미터 | |
extern int optind, //현재 처리중인 옵션의 argv 인덱스 | |
opterr, //이값이 참이면 getopt가 에러 메시지를 표시 | |
optopt; //현재 처리 중인 옵션 문자 | |
#define DEFAULT_N_LINES 10 | |
// [2] : 긴옵션을 정의하기 위해 struct 옵션의 배열을 만들고 각 긴 옵션에 해당하는 요소를 정의하였다. | |
//배열의 마지막에는 모든 멤버를 0으로 대입한 요소를 넣어야 한다. | |
//required_argument : 반드시 파리미터를 취함, no_argument: 파리미터를 취하지 않음 | |
//세번째 인자에 null을 입력하면 네번재 인자의 값이 반환된다. | |
static struct option longopts[] = { | |
{"lines" , required_argument, NULL, 'n'}, | |
{"help" , no_argument, NULL, 'h'}, | |
{0, 0, 0, 0} | |
}; | |
int main(int argc, char *argv[]){ | |
FILE *readFile; | |
int opt; | |
long linesNumber = DEFAULT_N_LINES; | |
//[3] :getopt_long : 커멘드 라인 옵션을 해석하는 api | |
//항상 루프와 사용하고 호출될때마다 인자로 넘겨진 다음 옵션 문자를 반환한다. | |
//잘못된경우 ? 를 반환한다. 인자로 넘겨진 모든 옵션을 반환했으면 -1을 반환한다. | |
while((opt = getopt_long(argc, argv, "n:" , longopts, NULL)) != -1) | |
{ | |
printf("opt - d : %d \n" , opt); | |
printf("opt - c : %c \n" , opt); | |
printf("optarg : %s \n" , optarg); | |
switch(opt){ | |
case 'n' : | |
linesNumber = atol(optarg); | |
break; | |
case 'h' : | |
//명령어 사용법 출력 | |
fprintf(stdout, "usage : %s [-n LINES] [FILE...] \n " ,argv[0]); | |
exit(0); | |
break; | |
case '?' : | |
//명령어 사용법 출력 | |
fprintf(stdout, "usage : %s [-n LINES] [FILE...] \n " ,argv[0]); | |
exit(1); | |
break; | |
} | |
} | |
printf("optind : %d \n" , optind); | |
//[7] : getopt_long에 의한 파싱이 끝난 시점에서 optind가 argc와 같다는 것은 | |
// 옵션 이외에 추가적인 인자를 지정하지 않았음을 의미한다. | |
//optind는 getopt()나 getopt_long이 마지막으로 처리한 인자의 인덱스를 가지고 있기 때문이다. | |
if(optind == argc){ | |
fprintf(stdout, "usage : %s 인자를 지정하세요 \n " ,argv[0]); | |
exit(1); | |
} | |
//오직 실행파일명 + 줄수 + 파일명 | |
if (argc < 2) { | |
fprintf(stderr, "usage: %s 예)실행파일명 + 줄수 + 파일명 \n" , argv[0]); | |
exit(1); | |
} | |
//파일을 읽기 전용으로 열기 | |
readFile = fopen(argv[2] , "r"); | |
//NULL 이면 파일 읽기 실패 | |
if (readFile == NULL) { | |
fprintf(stderr, "usage: %s 파일 열기 실패 \n" , argv[2]); | |
exit(1); | |
} | |
//표준파일 입력, atol: 문자를 long 타입의 숫자로 변환하는 함수 | |
//터미널에서 문자입력을 받는다. | |
do_head(readFile , linesNumber); | |
//파일 닫기 | |
fclose(readFile); | |
exit(0); | |
} | |
static void do_head(FILE *f, long nlines){ | |
printf("file : %p \n" , f); | |
printf("nlines : %ld \n" , nlines); | |
//줄 수가 0 보다 작으면 리턴 | |
if (nlines < 0) { | |
fprintf(stderr, "usage: %s \n" , "줄 수를 입력해주세요"); | |
exit(1); | |
} | |
/* | |
- getc | |
- 설명 | |
스트림에서 한 문자를 읽어온다. | |
문자를 읽어온 스트림의 내부 파일 위치 표시자가 현재 가리키는 문자를 리턴한다. | |
그리고 내부 파일 표시자는 그 다음 문자를 가리키게 된다. | |
- 인자 | |
문자를 읽어올 스트림의 FILE 객체를 가리키는 포인터 | |
- 리턴값 | |
읽어들인 문자는 int 값으로 리턴된다.만일 파일 끝에 도달하거나, 읽기 오류가 발생한다면 함수는 EOF 를 리턴하고 이에 대응하는 오류 혹은 EOF 표시자가 설정된다. 여러분은 ferror이나 feof함수를 통해 각각 어떤 오류가 발생했는지, 파일 끝에 도달하였는지 알 수 있다. | |
*/ | |
for (; ; ) { | |
//printf("start!\n"); | |
int c = getc(f); | |
//printf("c : %d \n" , c); | |
//결과 : 문자 a를 입력하고 엔터치면 97 과 10 출력한다. | |
//getc의 리턴값은 문자를 정수로 변환한 값을 1바이트씩 리턴한다. | |
//문자의 마지막을 만났을때 | |
if (c == EOF) { | |
break; | |
} | |
//엔터문자(줄바꿈) 만나면 nlines 변수 값 -1 | |
if (c == '\n') { | |
nlines--; | |
} | |
//커멘드 라인에서 입력한 줄수를 다 출력하면 빠져나온다. | |
if (nlines == 0) { | |
break; | |
} | |
//출력하기 | |
int p = putchar(c); | |
//printf("p : %d \n" , p); | |
//출력한 1byte 정수값을 리턴함 | |
//오류처리 | |
if (p < 0) { | |
exit(1); | |
} | |
} // for - end | |
printf("\n"); | |
} |
예제파일
#.homework
1.이전장에서 만든 \t 나 \n 을 출력해주는 기능을 cat 명령어의 옵션으로 켜고 끌 수 있게 작성하라.
2.파일의 마지막 몇 줄을 출력하는 tail 명령어를 구현하라. 출력하는 줄의 수는 고정값으로 한다.
#.이전장에서 만든 \t 나 \n 을 출력해주는 기능을 cat 명령어의 옵션으로 켜고 끌 수 있게 작성하라.
풀이
// \t -> '탭' 이나 \n -> '개행'으로 출력해주는 기능을 cat 명령어의 옵션으로 켜고 끌 수 있게 작성 | |
// 예) 명령어 : ./head -sy test.txt 또는 ./head -sn test.txt | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
//인자 처리 라이브러리 | |
#define _GUN_SOURCE | |
#include <getopt.h> | |
extern char *optarg; //현재 처리 중인 옵션의 파라미터 | |
//현재 처리중인 옵션의 argv 인덱스,에러, 현재 처리 중인 옵션 문자 | |
extern int optind, opterr, optopt; | |
//커멘드 라인 인자 옵션 구조체 | |
static struct option longopts[] = { | |
{"show" , required_argument, NULL, 's'}, //보이게, 숨기게 | |
{"help" , no_argument , NULL, 'h'}, //도움말 | |
{0, 0, 0, 0} | |
}; | |
int main(int argc, char *argv[]){ | |
FILE* readFile; | |
unsigned char buf[2] = ""; | |
long lSize; | |
int opt; | |
//show 옵션의 파라미터 y인지 n 인지 | |
char *yn; | |
//인자 개수 및 내용 출력 | |
printf("argc : %d \n" , argc); | |
for (int i =0 ; i < argc; i++) { | |
printf("argv [%d] : %s] \n" , i , argv[i]); | |
}; | |
//인자의 개수가 맞지 않을때 | |
if (argc != 3) { | |
fprintf(stdout, "usage:인자의 개수가 잘못되었습니다. \n %s -sy test.txt 또는 -sn test.txt 형식입니다. \n" , argv[0]); | |
} | |
//커멘드라인 인자 처리 | |
//getopt_long : 커멘드 라인 옵션을 해석하는 api | |
//항상 루프와 사용하고 호출될때마다 인자로 넘겨진 다음 옵션 문자를 반환한다. | |
//잘못된경우 ? 를 반환한다. 인자로 넘겨진 모든 옵션을 반환했으면 -1을 반환한다. | |
while((opt = getopt_long(argc, argv, "s:" , longopts , NULL)) != -1){ | |
switch(opt){ | |
case 's' : | |
//:s[파라미터] | |
yn = optarg; | |
break; | |
//도움말 | |
case 'h' : | |
fprintf(stdout, "usage: \n %s -sy test.txt 또는 -sn test.txt 형식입니다. \n" , argv[0]); | |
exit(1); | |
break; | |
//? | |
case '?' : | |
fprintf(stdout, "usage: \n %s -sy test.txt 또는 -sn test.txt 형식입니다. \n" , argv[0]); | |
exit(1); | |
break; | |
} | |
} | |
//getopt_long에 의한 파싱이 끝난 시점에서 optind가 argc와 같다는 것은 | |
//옵션 이외에 추가적인 인자를 지정하지 않았음을 의미한다. | |
//optind는 getopt()나 getopt_long이 마지막으로 처리한 인자의 인덱스를 가지고 있기 때문이다. | |
if(optind == argc){ | |
fprintf(stdout, "usage : %s 인자를 지정하세요 \n " ,argv[0]); | |
exit(1); | |
} | |
//argv[2]에 파일명이 존재 | |
//파일열기 - 읽기전용 | |
readFile = fopen(argv[2], "r"); | |
//파일 열기 오류 처리 | |
if (readFile == NULL) { | |
fprintf(stdout, "%s 오류가 발생했습니다." , argv[2]); | |
exit(1); | |
} | |
//파일 크기 구하기 | |
fseek(readFile, 0 , SEEK_END); | |
lSize = ftell(readFile); | |
rewind(readFile); | |
printf("##파일사이즈 : %ld byte\n" , lSize); | |
printf("##개행, 탭표시 유무 yn : %s\n" , yn); | |
//파일 읽기 | |
for (; ; ) { | |
int readByteNum = fread(buf, sizeof(char) , 1 , readFile); | |
//파일 다읽으면 빠져나오기 | |
if (readByteNum == 0) { | |
break; | |
} | |
//파라미터가 y면 리턴값 0 | |
int y = strcmp(yn, "y"); | |
//커멘드 라인의 옵션이 y이면 | |
if(y == 0){ | |
int retN = strcmp((const char *)buf, "\n"); // \n 문자열 비교 | |
int retT = strcmp((const char *)buf, "\t"); // \t 문자열 비교 | |
//개행표시 | |
if(retN == 0){ | |
// \n -> 개행 으로 출력 | |
fwrite("개행", sizeof(char) * 6 , 1 , stdout); | |
//탭표시 | |
}else if(retT == 0){ | |
// /t -> 탭으로 출력 | |
fwrite("탭", sizeof(char) * 3 , 1 , stdout); | |
} | |
} | |
//터미널에 표준출력 | |
fwrite(buf, sizeof(char) , 1 , stdout); | |
} | |
//파일 닫기 | |
fclose(readFile); | |
exit(0); | |
} |
결과

#.파일의 마지막 몇 줄을 출력하는 tail 명령어를 구현하라. 출력하는 줄의 수는 고정값으로 한다.
풀이
//파일의 마지막 몇 줄을 출력하는 tail 명령어를 구현하라. 출력하는 줄의 수는 고정값으로 한다. | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
//파일의 마지막 4줄 읽기 | |
#define lastTailNum 4 | |
int main(int argc, char *argv[]){ | |
FILE* readFile; | |
unsigned char buf[2] = ""; | |
long lSize; | |
int totalLine = 0; | |
//인자 개수 및 내용 출력 | |
printf("argc : %d \n" , argc); | |
for (int i =0 ; i < argc; i++) { | |
printf("argv [%d] : %s] \n" , i , argv[i]); | |
}; | |
//인자의 개수가 맞지 않을때 | |
if (argc != 2) { | |
fprintf(stdout, "usage:인자의 개수가 잘못되었습니다. \n %s test.txt 또는 test.txt 형식입니다. \n" , argv[0]); | |
} | |
//argv[2]에 파일명이 존재 | |
//파일열기 - 읽기전용 | |
readFile = fopen(argv[1], "r"); | |
//파일 열기 오류 처리 | |
if (readFile == NULL) { | |
fprintf(stdout, "%s 오류가 발생했습니다." , argv[2]); | |
exit(1); | |
} | |
//파일 크기 구하기 | |
fseek(readFile, 0 , SEEK_END); | |
lSize = ftell(readFile); | |
rewind(readFile); | |
printf("##파일사이즈 : %ld byte\n" , lSize); | |
//파일 읽기 - 파일의 전체 행 개수 구하기 | |
for (; ; ) { | |
int readByteNum = fread(buf, sizeof(char) , 1 , readFile); | |
//파일 다읽으면 빠져나오기 | |
if (readByteNum == 0) { | |
break; | |
} | |
int retN = strcmp((const char *)buf, "\n"); // \n 문자열 비교 | |
//개행 체크 | |
if(retN == 0){ | |
totalLine += 1; | |
} | |
} | |
//파일 읽은 위치 처음으로 되돌리기 | |
rewind(readFile); | |
// 마지막 n 번째 줄 까지 출력 | |
int lastOutLine = 0; | |
int nowNum = 0; | |
lastOutLine = totalLine - lastTailNum; | |
for (; ; ) { | |
int readByteNum = fread(buf, sizeof(char) , 1 , readFile); | |
//파일 다읽으면 빠져나오기 | |
if (readByteNum == 0) { | |
break; | |
} | |
//마지막 n 번째 줄 출력하기 | |
if(lastTailNum <= totalLine){ | |
if((lastOutLine <= nowNum) && (nowNum < totalLine)){ | |
//터미널에 표준출력 | |
fwrite(buf, sizeof(char) , 1 , stdout); | |
} | |
//개행 체크 | |
int retN = strcmp((const char *)buf, "\n"); // \n 문자열 비교 | |
if(retN == 0){ nowNum += 1; } | |
}else { | |
//전체 출력 | |
//터미널에 표준출력 | |
fwrite(buf, sizeof(char) , 1 , stdout); | |
} | |
} // for - end | |
printf("last tail num : %d \n" , lastTailNum); | |
printf("tatal line : %d \n" , totalLine); | |
fclose(readFile); | |
exit(0); | |
} |
결과

참고:모두를 위한 리눅스 프로그래밍
'컴퓨터 기초 > 운영체제 실습' 카테고리의 다른 글
14.파일 시스템 관련 api (0) | 2020.07.11 |
---|---|
13.grep 명령어 실습 (0) | 2020.07.04 |
[운영체제 실습] 11.시그널 (0) | 2020.07.03 |
[운영체제 실습] 10.프로세스 생성과 실행 (0) | 2020.06.28 |
[운영체제 실습] 9.프로세스 (0) | 2020.06.28 |