質問

【C言語】コマンドライン引数の標準入出力

コマンドライン引数で、ファイル名を3つ渡します。-aの次のコマンドライン引数が、出力ファイル名です。

<<例>>
・実行モジュール -a 出力ファイル名 -b ファイル名 -c ファイル名

・実行モジュール -c ファイル名 -a 出力ファイル名 -b ファイル名

もし出力ファイルが指定されなかった場合に、標準入出力を使いたいのですが、どうしたらいいかわかりません。
下記がソースの一部です。これをどう改造したらよいでしょうか。
分かる方いらっしゃいましたらご回答いただけると幸いです。
宜しくお願いします。

//出力ファイルを取得、書き込みモードでオープン
for(j=1;j<argc-1;j++){
if(strcmp(argv[j],"-o")==0){
if((fo = fopen(argv[j+1],"w"))==NULL){
printf("open error!!\n");
exit(1);
}
}
}
while(fgets(buf,sizeof(buf),fp)!= NULL){
if(strstr(buf,"keyword")!= NULL){
//出力ファイルに出力
fprintf(fo,"%d:%s",line,buf);
}
}

通報する

回答 (4件)

> -aの次のコマンドライン引数が、出力ファイル名です。

コードでは -o となってるけど?
別の回答者さんの言うように、fopen() は後回しにした方がいいでしょう。

> for(j=1;j<argc-1;j++){

これだと最後の引数を評価してませんよ?
全てが -o file みたいならいいですが、file が必要ないスイッチがあるとまずくありませんか?

FILE * fo = stdout;
char * outf = NULL;

for(j=1;j<argc;j++){
if(strcmp(argv[j],"-o")==0){
if (++j < argc) {
if (outf) {
fprintf(stderr, "duplicate -o option\n");
exit(1);
}
outf = argv[j];
} else {
fprintf(stderr, "-o option requires a output filename\n");
exit(1);
}
}
}

if (outf && (fo = fopen(outf, "w"))==NULL){
printf("open error!!\n");
exit(1);
}

この回答へのお礼

おかげ様で解決できました。
ご回答ありがとうございました。

追記。

>本来「すべてのコマンドライン引数を評価し終わるまで、fopenなどの実質的な処理を開始しない方が良い」でしょう。

回答の前半に書いた「引数を評価しながらfopenしちゃうプログラム」で
実行モジュール -o 出力ファイル名1 -b ファイル名 -c ファイル名 -o 出力ファイル名2 -o 出力ファイル名3
って実行したら「中身が空の『出力ファイル名1』が作成されてしまってから、duplicate -o switch!ってエラーが表示されて停止してしまう」と思います。

質問者さんも「エラー表示して止まるんだったら、中身が空の『出力ファイル名1』が作成されない方が良い」と思いませんか?

なので「すべてのコマンドライン引数を評価し終わるまで、fopenなどの実質的な処理を開始してはいけない」のです。

この回答へのお礼

なるほど、fopenを後回しにするとできました。
非常に参考になりました。ご回答ありがとうございました。

#include <stdio.h>
 fo = NULL;
 for(j=1;j<argc-1;j++){
  if(strcmp(argv[j],"-o")==0){
   if(fo != NULL){
    fclose(fo);
    printf("duplicate -o switch!!\n");
    exit(1);
   }
   if((fo = fopen(argv[j+1],"w"))==NULL){
    printf("open error!!\n");
    exit(1);
   }
  }
 }
 if(fo == NULL){
  fo=stdout;
 }
 while(fgets(buf,sizeof(buf),fp)!= NULL){
  if(strstr(buf,"keyword")!= NULL){
   //出力ファイルに出力
   fprintf(fo,"%d:%s",line,buf);
  }
 }
 if(fo != stdout){
  fclose(fo);
 }

本来「すべてのコマンドライン引数を評価し終わるまで、fopenなどの実質的な処理を開始しない方が良い」でしょう。

つまり

#include <stdio.h>
#undef FIRST_SWITCH_ENABLED
 FILE *fo;
 char *fo_name;
 fo = NULL;
 fo_name = NULL;
 for(j=1;j<argc-1;j++){
  if(strcmp(argv[j],"-o")==0)){
#ifdef FIRST_SWITCH_ENABLED
   if(fo_name == NULL) //このif文があると「最初の-oが有効」で、if文が無いと「最後の-oが有効」になる
#endif
    fo_name = argv[j+1];
  }
 }
 if(fo_name != NULL){
  if((fo = fopen(fo_name,"w"))==NULL){
   printf("open error!!\n");
   exit(1);
  }
 }else{
  fo=stdout;
 }
 while(fgets(buf,sizeof(buf),fp)!= NULL){
  if(strstr(buf,"keyword")!= NULL){
   //出力ファイルに出力
   fprintf(fo,"%d:%s",line,buf);
  }
 }
 if((fo_name != NULL)&&(fo != NULL)){
  fclose(fo);
 }

とします。

これで、
実行モジュール -o 出力ファイル名1 -b ファイル名 -c ファイル名 -o 出力ファイル名2 -o 出力ファイル名3
と書かれた場合も、引数の解析の途中でエラーで止めずに済みます。

「最初の-o」か「最後の-o」のどちらを有効にするかは、コメントを付けたif文の有無で決まります。

if文の有無は、識別子「FIRST_SWITCH_ENABLED」を定義するか未定義にするかで決まります。

起動後の処理に
コマンドライン引数の内容をチェックする処理を加えればいいのよ。
指定があれば変数fileOutputFlg=trueにして、ファイルを開く。
なければfalseにしておいて。

出力は、例えばwriteLog("",,,)という関数で行い
その中で
fileOutputFlgがtrueならファイルハンドラ、
falseなら標準出力に出力

こんな感じね。

この回答へのお礼

なるほど、参考にさせていただきます。
ご回答ありがとうございました。

このQ&Aは役に立ちましたか?2 件

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

新しく質問する

注目の記事

おしトピにAndroid版アプリが登場

話題のトピックにさくっとコメントできる「おしトピ」に Android版アプリが登場! もっと身近に使いやすくなりました。
今ならダウンロードで話題の掃除ロボットや全天球カメラが 当たるプレゼントキャンペーンも実施中。


新しく質問する

このカテゴリの人気Q&Aランキング

毎日見よう!教えて!gooトゥディ

べんりQ&A特集