• ベストアンサー

execvpでのcdコマンドについて。

簡単んなシェルプログラミングを組んでいます。 そこである問題にぶつかっています。 ******************************************** int main() { int argc, n = 0; pid_t pid; int status; char input[MAX_LEN], *argv[MAX_ARGS]; char path[30]; while (1) { /* プロンプトの表示 */ ++n; printf("command[%d] ", n); fgets(input, MAX_LEN, stdin); /* 改行を除去し、 空白,タブ区切りでコマンド列に分割、argvに単語毎に格納 (処理は略) */ sprintf(path,"%s",argv[0]);//PATH取得 pid = fork(); /*#### 子プロセス ####*/ if(pid == 0){ execvp(path,argv); exit(0); } /*#### 親プロセス処理 ####*/ } else { wait(&status); } }//while }//main としています。 ここで ls ps rm mkdir emacs などのコマンドは普通につかえるのですが、 cd .. や、 mkdir test cd test としてもそのディレクトリへ移動することができません。どうすればいいでしょうか?このプログラムをうごかしたままディレクトリを移動することは可能でしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.5

おおよそ、他の方が書かれてますが、カレントディレクトリはプロセス固有の値で親から子へは継承されますが、子プロセス内で変更しても親へは伝わりません。 対応としては、コマンドがcdであることをチェックして、その場合は、fork&exec でなく、自分のプロセス内でchdirというシステムコールでカレントディレクトリを変更します。 環境変数PWDの話が出ていますが、カレントディレクトリと環境変数PWDには直接の関係がありません。PWDも変更したいならさらにsetenvサブルーチンで変更します。 話は変わって、 >execvp(path,argv); >exit(0); となっていますが、execvpの次の文が実行されるのはexecvpが失敗した時(pathで指定したファイルが無い等)なので、エラーメッセージを出したほうが良いでしょう。最初にそうしていれば、cd を入力するとエラーになる(cdはシェル組み込みコマンドで、cdというファイルは無いため)ので気づいたかも。 つまり、実は cd test と入れたときには子プロセスでtestにカレントディレクトリが移って親に反映しなかったわけではなく、execvpが失敗してexit(0)で子プロセスが終了していたと思われます。いずれにせよ対応は上に書いた通りでOKです。 シェルには多くの組み込みコマンドがあるので、それらのどこまで組み込むかが考えどころですね。cd のように組み込み処理が必須のコマンドもあれば、echo や test のようにコマンドファイルとしても存在するのに速度向上のために組み込みコマンドになっているものと二通りあります。

その他の回答 (5)

noname#6200
noname#6200
回答No.6

何か結局私が混乱させていたようですので役に立つか分かりませんがcdの引数無しでホームに移る部分書いておきます。 お騒がせしました。 if(argv[1] == NULL){ if(chdir(getenv("HOME")) <0) perror("cd"); } else{ if(chdir(argv[1]) <0) perror("cd"); }

noname#6200
noname#6200
回答No.4

なんか私はいろいろ勘違いしていたようですね。 どうやら断食中で頭がぼーっとしているようです。 環境変数PWDの問題じゃないんですがカレント作業ディレクトリは継承されています。 どのように継承されてるかはちょっと私には分かりませんが・・・。 cdってshに組み込まれてるんですよねたしか。 だから扱いが難しそうですね。 難しそうですがUNIXのシェルのソースを見てみるのも手だと思います。

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.3

ummuさんの言われている通り、コマンドcdに関しては、子プロセスにforkして実行するのではなく、カレントプロセス内で実行する必要があります。 子プロセスでcdしても、親プロセス(=shellとして機能している方)には影響しないので。 which cdの結果を見ると、分かるかも。

noname#6200
noname#6200
回答No.2

No.1ですがまたまたすみません。 環境変数PWDを毎回継承するからじゃないみたいです。 御迷惑お掛けしました。

arcsin
質問者

お礼

あ、行き違ってしまいましたね^^; 環境変数の問題じゃないんですか・・・、ちょっと先ほどのご回答で納得してしまっていました(笑 今もまだ抜けられずにいます。。

noname#6200
noname#6200
回答No.1

前の質問で全然回答になっていなくて混乱させてしまったものと思われます。すいません。 同じもの書いてみましたが引数をとれると思います。 argvへの格納がおかしいのでは? cdに関してですが毎回新たに子プロセスを生じているため子プロセスは親プロセスの環境変数PWDを継承しています。 このプログラムでは別にforkする必要が無いように思えます。

arcsin
質問者

補足

再びご回答ありがとうございます >>argvへの格納がおかしいのでは? argvの中身を確認したところ、 cd testとしたところ、 argv[0]=cd, argv[1]=test と格納されていましたので、ここは大丈夫だと思います。 >>cdに関してですが毎回新たに子プロセスを生じているため子プロセスは親プロセスの環境変数PWDを継承しています。このプログラムでは別にforkする必要が無いように思えます はじめ親プロセスにexecvpを記述したところ、プログラム起動後、一回のコマンドでプログラムが終了してしまいました。なので子プロセスを生成しないと、exec系でこのプログラムが終わってしまうようなんです。まだforkを使い始めたばかりで知識があまりないのですが。以下のように把握してよろしいでしょうか。 このプログラムだとcdのコマンドは子プロセスで実行する事になる。その後に行うコマンドは、親プロセスから継承した環境変数をもつ新たに生成された子プロセスだから、また同じフォルダにいることになる。 もしそうであれば何か解消方法はあるでしょうか。