The Office Uchida, School of Computer

コンピュータを学習する人の学校:パソコンキャンパス、プログラミングキャンパス
ホームCプログラマ徹底養成コース初級コース 第20問/中級コース 第12問/上級コース 第5問
文字の拡大

初級コース 第20問/中級コース 第12問/上級コース 第5問:簡易grepコマンド

問題:Unixのgrepコマンドの簡易版easygrepコマンドを作ってください。

easygrepコマンドは、次の構文をしています。

easygrep pattern filename

このコマンドを実行すると、まず、filenameからファイルを読み出し、その中に文字列patternが ないかどうかチェックして、もしあれば、その行を行番号とともに表示します。

参考のために、コンパイル例を含めて、実行例を示します。このコマンドのプログラムが、easygrep.cに格納されているとします。

まず、Unix系OS(gccを含む)の場合には、次のコマンドでeasygrepというコマンドを作ります。

% gcc -o easygrep easygrep.c

そして、次のコマンドでeasygrep.cというファイルの中からstderrを含む行をその行番号とともに表示します。

% easygrep stderr easygrep.c
   18 :                 fprintf( stderr, "Usage: easygrep pattern file\n" );
   27 :                 fprintf( stderr, "file:%s not found\n", filename );
   41 :                 fprintf( stderr, "何らかの入出力エラーが発生しました。\n" );

学習ポイント
  1. コマンドの作り方を覚える
  2. 文字列の扱いに慣れる

本問題に対するFAQ

質問1:コマンドのパラメータは、どのように取得すればよいのですか。

 main関数の引数にパラメータ数とその文字列を取得する配列を指定します。次のサンプルプログラムを ご覧下さい。

Sample list  argtest.c
#include<stdio.h>

int main( int argc, char *argv[] )
{
	printf( "argc = %d\n", argc );

	while( argc-- )
		printf( "argv[%d] : [%s]\n", argc, argv[argc] );

	return 0;
}

まず、このプログラム(argtest.c)を次のようにコンパイルします(Unix系の場合)。Windows系OSのコンパイラ(Visual C++など)では、 コンソールアプリケーションのEXEファイルを作ってそれを実行してください。

% gcc -o argtest argtest.c

そして、まず、次のようにパラメータを指定しないで実行します。すると、argc=1となり、配列要素には1つだけ文字列がセットされます。 この場合、その文字列には、コマンド名が入っているようですが、これはOSやコンパイラなどによって多少異なります。

% argtest
argc = 1
argv[0] : [argtest]

次の例は、パラメータを1つ指定します。パラメータは、あくまでも空白で区切るという規則なので、その中にコンマがあっても 1つのパラメータとして扱われます。

% argtest 1,2,3
argc = 2
argv[1] : [1,2,3]
argv[0] : [argtest]

次の例はさらにいろいろとパラメータを指定した例です。

% argtest 1 2 3:4:5 "test" ::: ++
argc = 7
argv[6] : [++]
argv[5] : [:::]
argv[4] : [test]
argv[3] : [3:4:5]
argv[2] : [2]
argv[1] : [1]
argv[0] : [argtest]

Unix系(Cygwinを含む)OSでは、パラメータにおいて、*は特別な意味を持ってしまいます。つまり、これは、 そのフォルダ(ディレクトリ)の中でそのパターンにマッチしたファイル名に変換されます。

% argtest *
argc = 57
argv[56] : [temp.txt]
argv[55] : [n2.html]
argv[54] : [n2.c]
argv[53] : [intest.dat]
 ...(略)...
argv[2] : [ConvertProgram.class]
argv[1] : [CommentStatus.class]
argv[0] : [argtest]

これを回避するには、"*"とします。

% argtest "*"
argc = 2
argv[1] : [*]
argv[0] : [argtest]