【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);
}
}

このQ&Aに関連する最新のQ&A

A 回答 (4件)

追記。



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

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

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

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

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

お礼日時:2010/08/04 17:02

> -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);
}
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/08/04 17:01

#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」を定義するか未定義にするかで決まります。
    • good
    • 1

起動後の処理に


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

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

こんな感じね。
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/08/04 17:04

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qコマンドライン引数の例外処理について

整数a、bをコマンドライン引数として受け取るプログラムを作成するとします。この時、入力するコマンドライン引数を整数であるa、b2つのみとします。

次の事柄について教えて下さい。

(1)コマンドライン引数を2個入力しなかった時の例外処理の仕方
(例えば、コマンドライン引数を入力しなかったり3個入力した時)

(2)整数のコマンドライン引数を入力しなかった時の例外処理の仕方
(例えば、「abc」などと入力した場合)

(3)コマンドライン引数を数の小さいものから入力しなかった時の処理の仕方
(例えば、「3 5」ではなく「5 3」と入力した場合)

初心者なもので…。どなたかお教え下さい。宜しくお願いします。

Aベストアンサー

public static void main(String[] args) {
//引数の範囲チェック
int nLen = args.length;
if(nLen != 3){
System.out.prinln("引数の個数が違います");
return;
}
int nCheck = 0;
for(int nRpCnt=0;nRpCnt<nLen;nRpCnt+){
int nNum = 0;
try{
nNum = Integer.parseInt(args[nRpCnt],10);
}catch(NumberFormatException nfe){
System.out.prinln(
     "引数["+nRpCnt+"]が数字ではありません");
    return;
}
//昇順チェック

}

}

以上。。。。。

QC言語でコマンドラインの引数について。

コマンドラインで引数をわたす基本的なプログラムは
main(int argc,char *argv[]){....]
ですよね。
今回実行時に、
>実行ファイル名 123 + 233
といれたら、123+233を計算してくれるプログラムを作ろうとしています。
その場合、main(int argc,int *argv[]){}
としたら、argv[1]に123が入って、argv[2]に+が入って、argv[3]に233が、入るというわけではないんでしょうか?
とりあえず、確認で
#include<stdio.h>
main(int argc,int *argv[])
{
printf("%d\n%d\n",argv[1],argv[3]);
}
としてみたんですが、実行結果は、とても長い数字がでてきてきました。
なにがいけないのか教えてください。
お願いします。
あとWindows MEでVC++6を使ってます。

Aベストアンサー

C は、コマンドラインから渡された文字列をStartup ルーチンが解釈
してmain 関数を呼び出すようになっていますので、パラメータを受け取る
側の引数の型だけを変更しても意味がありません。
→ 結局は、文字列を格納したアドレスが渡ってきます。

数値型に変換する場合は、
main(int argc, char *argv[])
{
int val1, val2;
val1 = atoi(argv[1]);
val2 = atoi(argv[3]);

}
のように、変換してやる必要があります。
※ 上記のプログラムは、パラメータの数をチェックしていませんのが、
  実際のプログラムではパラメータの数をチェックを忘れないように
  して下さい。

QYahooブリーフケースにコマンドラインからファイルをアップロードするには?

Yahooブリーフケースにコマンドラインからファイルをアップロードしたいのです。
どのようにコマンドすればいいのでしょうか?

Windows2000の環境です。
コマンドラインは
コマンドプロンプトとCygwinがあります。

Aベストアンサー

コマンドラインでのアップロードには対応していません

Qコマンドライン引数の区別【C言語】

コマンドライン引数の区別【C言語】

コマンドラインから二つの引数(ファイル名)を渡すとき、順番が替わっても大丈夫なようにして、それぞれファイルオープンをしたいです。(エラーで”順番が違います”と出力するのはNGです)
どうしたら区別できますか。分かる方いらっしゃいましたらご教授願います。
サンプルコードを書いていただけると幸いです。
宜しくお願いします。

Aベストアンサー

コマンドで指定する入力ファイルと出力ファイルの順を自由にするということなら、コマンドラインを明確にする手法としては次のような仕様にする方法があります。
command -i input_file_name -o output_file_name
あるいは
command -o output_file_name -i input_file_name
とコマンドラインを書かせる。

この仕様なら、コマンドライン引数argvを順にみていって、例えばargv[1]が"-i"ならargv[2]には入力ファイル名が入っているし、argv[1]が"-o"ならargv[2]には出力ファイル名が入っている。そういうどちらの場合でも解釈できるコマンドラインオプションの解析をするプログラムを書くだけです。
Cではコマンドライン解析を簡単にする標準ライブラリはなかったと思うので、自作するか、適当なものをネットで見つけてください。

そういうのでなく、二つ並べた名前から一方は入力で一方は出力だと判断するのは、追加情報がなければ一般的に無理です。

Qコマンドとコマンドラインとコマンドラインオプションの違いを教えてください。

ただ今Cの関数を勉強しているのですが、勉強用HPに

************************

int main(int argc, char *argv[ ])

戻り値:int型、引数:argc, argv

後者は、コマンドライン オプションを受け付ける。 argc はオプションの数、argv はオプションの内容となる。

************************

とあります。

そこで質問なのですが、コマンドラインオプションとは何ですか?
また、

・コマンド
・コマンドライン
・コマンドラインオプション

の違い、それぞれの意味も教えてください。

マックのコマンド+s、コマンド+vみたいなものですか?
それともunixのcdや./のようなものでしょうか。

わからない単語が出てくると、
そこで頭が混乱してしまい先に進めない性質なので困っています。

どうぞご教授よろしくお願いします。

Aベストアンサー

★回答
・『コマンド』とは
 プログラム名の事です。
 つまり unix でいうと cd、cp、ls などです。
・『コマンドライン』とは
 プログラム名 引数 … 引数、オプションの1行の事です。
 または、コマンドを打ち込む入力待ちの状態です。
・『コマンドラインオプション』とは
 cp コマンドでいう -f、-i、-p、-r などの事です。
 cp コマンドでのファイル名は引数と呼びます。
 一般にオプションは - 文字から始まります。
 あと Windows の OS では / 文字から始まるスイッチオプションという呼び方がありますが、
 - 文字から始まるオプションとほぼ同じ役割です。また、- 文字、/ 文字から始まるものを
 合わせてオプションと呼ぶこともあります。

その他:
・main() 関数の引数にある『argc』は引数の個数、『argv』は引数の内容です。
 参考にした HP ではオプションの数、オプションの内容と呼んでいますが、引数もオプションも
 含まれます。引数とオプションはプログラムで区別するため、そのために - 文字や / 文字から
 始まる文字列をオプション(スイッチ)などとして区別しています。もし、- 文字や / 文字から
 始まらない文字列ならば、それが引数とプログラムで解釈するように C ソースを記述します。
・具体的にはコマンドラインで『cp -i -r file1.c file2.c』と入力するとプログラムでは、
 argc = 5
 argv[ 0 ] = "cp" ←プログラム名
 argv[ 1 ] = "-i"
 argv[ 2 ] = "-r"
 argv[ 3 ] = "file1.c"
 argv[ 4 ] = "file2.c"
 argv[ 5 ] = NULL ←必ずセットされる
 となります。
・argc はオプションと引数の合計数です。また、プログラム名もカウントされます。
 その他、argv[0] にプログラム名が入るか、空文字列が入るかは処理系依存です。
 あと argv[ argc ] の位置には必ず NULL ポインタがセットされることが保障されています。
・以上。参考に!

★回答
・『コマンド』とは
 プログラム名の事です。
 つまり unix でいうと cd、cp、ls などです。
・『コマンドライン』とは
 プログラム名 引数 … 引数、オプションの1行の事です。
 または、コマンドを打ち込む入力待ちの状態です。
・『コマンドラインオプション』とは
 cp コマンドでいう -f、-i、-p、-r などの事です。
 cp コマンドでのファイル名は引数と呼びます。
 一般にオプションは - 文字から始まります。
 あと Windows の OS では / 文字から始まるスイッチオプションという...続きを読む

QC言語でのコマンドライン引数の内部での処理のされ方

C言語でint main(int argc, char *argv[])とメイン関数を宣言します。

2番目の引数はC言語の文法的にいうと文字列へのポインタの配列だとおもいますが、一般的な関数でこの引数に値を渡すとすると、以下のように宣言されたポインタ配列を渡すことになるとおもいます。

・宣言
char *pa[];
・関数への渡し
func(pa);

話が元に戻りますが、main関数でもらう場合は、プログラム外部から与えられた引数は(正確に言うとアドレス)、メモリ上ではC言語で書かれたexeファイルの外から実行時にプログラムファイルのメモリ上にコピーされるのでしょうか?

自分でもうまく表現できないのですが、
・コマンドプロンプトで引数を与えて実行
        ↓
・プログラムファイルのメモリ上に引数がロードされる
ということでいいんでしょうか?

自分でもなんだかうまく表現できないので、お暇な方でよろしいので、気が向いた人、回答ください。

よろしくお願いします。

Aベストアンサー

★ちょっと昔話。
・Windows より前の OS MS-DOS では、プログラムが実行されるとメモリ上に存在する
 EXE ヘッダにコマンドラインの文字列と文字数が格納されます。
 そして、C 言語で作成されたプログラムは main() 関数を実行する前にスタートアップ
 ルーチンという処理が行われます。この処理の中に EXE ヘッダに存在するコマンドライン
 文字列のコピーを作ります。その後、スペースで区切られた引数を char *argv[] に
 セットしてから main() 関数が呼び出されます。
・よって、まとめると
 (1)コマンドラインから実行
 (2)プログラムをメモリ上にロード(EXE ヘッダに引数文字列がセットされる)
 (3)スタートアップ処理で EXE ヘッダから C 言語のグローバル変数領域に引数文字列をコピー
 (4)コピーされた引数文字列をスペース文字で区切って char *argv[] 配列にセット
 (5)main() 関数に char *argv[] と区切った引数の個数を argc で渡す
 ↑
 簡単に説明するとこんな感じになります。
・引数文字列はコピーしたものを *argv[] で使うため EXE ヘッダにある引数文字列は
 書き換わりません。→正しくは EXE ヘッダにある引数文字列は書き換えてはいけない。
・上記のは MS-DOS という OS の話です。でも Windows のプログラムも同様な処理を行っている
 と思います。EXE ヘッダ(PE情報)があるので。MS-DOS 時代よりも PE ヘッダが複雑でサイズが
 増えていますね。この PE 情報の資料がほとんど見つかりませんね。英語サイトならありますが…。

最後に:
>・プログラムファイルのメモリ上に引数がロードされる
 ↑
 プログラムファイルのメモリ上(EXEヘッダ)に引数文字列がロードされる
 その後、プログラムのグローバル変数領域に引数文字列がコピーされる
 そして、コピーされた引数文字列をスペース文字で分割される
 そしたら main() 関数の char *argv[] として引数文字列が渡される
 という順になります。
・ちなみに Windows API 関数に引数文字列を取得する GetCommandLine() があります。
 これは多分、EXE ヘッダの引数文字列から直接ポインタで取得しているような気がします。
 理由は、この関数で取得した引数文字列は書き換えないようにという注意書きがあるので。
 でも、本当のところはよく分かりませんが…。注意書きを信じてコピーしてから使いましょう。
・他の OS については詳しく知りませんので 昔の MS-DOS、そして Windows 系で回答してみました。
・以上。

参考URL:http://wisdom.sakura.ne.jp/system/winapi/win32/win6.html

★ちょっと昔話。
・Windows より前の OS MS-DOS では、プログラムが実行されるとメモリ上に存在する
 EXE ヘッダにコマンドラインの文字列と文字数が格納されます。
 そして、C 言語で作成されたプログラムは main() 関数を実行する前にスタートアップ
 ルーチンという処理が行われます。この処理の中に EXE ヘッダに存在するコマンドライン
 文字列のコピーを作ります。その後、スペースで区切られた引数を char *argv[] に
 セットしてから main() 関数が呼び出されます。
・よって、まとめると
 ...続きを読む

Qコマンドラインがわかりません!!

(質問)
(1)コマンドラインというのがわかりません。
(2)下の説明のところが全部わかりません。
よろしくおねがいします!!
--------------------------------------------------
(説明)

ファイルを処理するとき、ファイル名指定はコマンドラインから行うのが便利です。Javaではコマンドライン引数はmain( )メソッドの引数として次のように用意されています。

public static void main (String args[ ]) {
・・・・・
}

このargs引数を使うと、コマンドラインから入力されたパラメーターを次のように取得できます。
最初のパラメーター文字列は0です。

args.length
args[0]
args[1]
args [2]
 ・
 ・
 ・

Aベストアンサー

#2のbakatonoです.長くなります.すみません.

>すいませんここをもう一度お聞きしたいのですがfile1 file2は
>ファイルそのものじゃなくて文字列とはどういうことですか?

そのままの意味ですよ.

実行するコマンド(プログラム名)のあとに,スペースで区切って入れた
文字列が全て「コマンドライン引数」です.スペースで区切って複数書くと,
前から順番にプログラムに渡され,args[]にそのままの順番で入ります.

>a bとかだったら文字列になるのはわかるんですが、file1 file2って
>ファイルですよね?それが文字列になるというのがわかりません。
>ファイル自体が引数として渡されないんですか?

コマンドライン引数は基本的に文字列として渡します.なぜならそれが一番都合がいいからです.
コマンド(プログラム)は,ファイルをいじくるだけのものとは限りませんよね?
「文字列をごにょごにょする」ものもあるでしょうし,「数値をがちゃがちゃする」
ものもあるでしょう.

私が前に挙げた例(例1とします)は,hoge.exeが「二つのファイルをもにょもにょする」
というプログラムだった場合の例といえます.
この場合,渡されたファイル名の文字列を使って,プログラム内で該当するファイル
をオープンして,それらのファイルをもにょもにょ処理することになります.

例2)
文字列を2つ渡して,一つ目の文字列の中に二つ目の文字列がいくつ含まれるかを
数えるプログラム「gonyo.exe」の場合
c:\>gonyo.exe hogehogeauau au ←コマンド(プログラム)とコマンドライン引数
c:\>2             ←実行結果
hogehogeauauが第1引数,auが第2引数で.プログラム内部でごにょごにょ数えたら
hogehogeauauという文字列の中にauという文字列が2回含まれてました.
こんなプログラムを組みたい場合,渡したいのは文字列そのものですよね?

また
例3)
数字を2つ渡して,一つ目の数字と二つ目の数字の合計を求めるプログラム
「keisan.exe」の場合
c:\>keisan.exe 3 5 ←コマンドとコマンドライン引数
c:\>8        ←実行結果
こんなプログラムの場合,渡したいのは数字ですが,文字列として渡して,
プログラムの内部で文字列→数値変換してガチャガチャ計算すればいいのです.

さらにいうと,上記例の混在するケースも考えられます.ファイル名と数字を与えて,
そのファイルを数字の数だけ分割するプログラム...とか,いくらでもあります.

ね?とりあえず文字列で渡すのが一番都合がいいでしょう?
プログラム内部で好きなように使う.これでどんなパターンにも柔軟に対応できます.

==蛇足==
こういうのを,「汎用性(が高い)」と言い,プログラミングではとても重要なことの
ひとつであることを覚えておきましょう.がんばって勉強してくださいね^^

#2のbakatonoです.長くなります.すみません.

>すいませんここをもう一度お聞きしたいのですがfile1 file2は
>ファイルそのものじゃなくて文字列とはどういうことですか?

そのままの意味ですよ.

実行するコマンド(プログラム名)のあとに,スペースで区切って入れた
文字列が全て「コマンドライン引数」です.スペースで区切って複数書くと,
前から順番にプログラムに渡され,args[]にそのままの順番で入ります.

>a bとかだったら文字列になるのはわかるんですが、file1 file2って
>ファイ...続きを読む

QVC++でコマンドラインから引数を渡す方法

さっきも違う質問でお世話になったものです。またわからないことがあったので、質問させてもらいます。
タイトルのとおりなんですが、現在Visual C++ 6でC言語の勉強をしてるんですが、コマンドラインから引数を渡すにはどうすればいいんでしょうか?
main(int arfc,int *argv[]){
・・・・
・・・・}
のようなプログラムなんですよ。
C言語もVC++の使い方をもよく分かってないので、詳しく教えてもらえるとうれしいです。
過去の質問も調べてみたんですが、似たような質問は見つかったんですが、わからなかったので、質問させてもらいました。
よろしくお願いします。

Aベストアンサー

ビルド設定項目のひとつとして'コマンドライン'があるはず。

QJAVAのコマンドラインについて

コマンドラインで-sを入れた時に
String uwagaki = "-s"
if (uwagaki.equals(args[0]))
とこうしてコマンドラインで入れたのは-sなのかifで確認しています。
しかし、コマンドラインを入力しないとエラーが起こってしまいます。
どのように対処したらいいでしょうか?

Aベストアンサー

String s;
if (args.length > 0) {
s = args[0];
} else {
s = "";
}
if (uwagaki.equals(s)) {
...
}
とすれば、OK。

Qコマンドラインから引数を渡したいのですが・・・

VC.NETで参考書に載っていた下のようなコードを書きました。
#include <iostream>
#include <cstdlib>
using namespace std;

int main (int argc, char *argv[])
{
int sum;

if (argc != 3)
{
cout << "引数の個数が違います。";
return 1;
}
sum = atoi (argv[1]) + atoi (argv[2]);
cout << "合計=" << sum << '\n';

return 0;
}
しかしながら、引数の個数が違います。としか出力されません。どうすればよろしいでしょうか?

Aベストアンサー

VCにて実行した場合はコマンドライン文字列を入力していないので、
argcは1、
argv[0]は[プログラム名]文字列へのポインタとなります。

したがって、コンパイル後にコマンドプロンプトを起動して
prog.exe 111 222
のように入力するか、
または、VC上で[プロジェクト]-[プロパティ]-[構成プロパティ]-[デバッグ]の[コマンド引数]に
111 222
のように入力する必要があります。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング