headコマンドを作る


今回は、headコマンドの原型の作り方について勉強しました。
headコマンドとは指定したテキストファイルの内容を、頭から指定した行数だけ表示するプログラムです。
行数指定は本来、-nのオプションを伴って記述しますが、今回は簡単のため一つ目のコマンドライン引数を行数としています。


/* myhead.c */
#include<stdio.h>
#include<stdlib.h>

static void do_head(FILE *f, long nlines); /* do_headのプロトタイプ宣言 */
/*ファイルに接続されたストリームから与えられた行数だけ読み込む関数*/
int main(int argc, char *argv[])
{
long nlines;

if(argc <  2){
        fprintf(stderr, "Usage: %s n [file file ...]\n", argv[0]); /*コマンドライン引数が無い時はエラーメッセージを表示*/
                exit(1);
 }
nlines = atol(argv[1]); /* 二番目のコマンドライン引数をlong型に変換 */
if(argc == 2){
do_head(stdin, nlines); /*コマンドライン引数が一つの時は標準入力を処理*/
} else{
int i;
for(i = 2; i< argc; i++){
FILE *f; /* ファイルディスクリプタのラッパーのFILE型ポインタを宣言 */
f = fopen(argv[i], "r");
if(!f){ /*f!はf!=NULLと同じ*/
perror(argv[i]);
exit(1);
}
do_head(f, nlines);
fclose(f);
}
}
exit(0);
}

static void do_head(FILE *f, long nlines)
{
int c; /*getcの戻り値はint型であることに注意*/
if(nlines <= 0) return; /*行数カウンタが0なら関数から抜ける*/
while((c = getc(f)) != EOF){ /* getcでファイルにつながれたストリームから一文字ずつ読み込む(EOFまで)*/
if(putchar(c) < 0) exit(1);
if(c=='\n'){
nlines--; /*改行コードに当たったら文字カウンタをデクリメント*/
if(nlines == 0) return; /*行数カウンタが0なら関数から抜ける*/
}
}
}



#コンパイル
$ gcc -o myhead myhead.c

#読み込むファイル作成
$ vi test.txt

#中身を確認
$ cat test.txt
agc
def
ghi
jkl

#

$ ./myhead 4 test.txt
agc
def
ghi
jkl

$ ./myhead  test.txt
agc
def

#エラーを出してみる
$ ./myhead
Usage: ./myhead n [file file ...]