C で独自の Unix シェルを作成する - PATH と execv に関する問題
質問
私はCで独自のシェルを書いています。ユーザーの現在のディレクトリを表示し、フルパスに基づいてコマンドを実行できる必要があります(execvを使用する必要があります)、ユーザーが cd でディレクトリを変更できるようにします。
これは宿題です。先生は私たちに C の基本的な入門書と、プログラムがどのように動作するかについての非常に簡単な骨子だけを教えてくれました。私は簡単にあきらめない性格なので、これを行う方法を3日間調べてきましたが、今では途方に暮れています。
これが私がこれまでに持っているものです:
- ユーザーのユーザー名、コンピュータ名、および現在のディレクトリ (デフォルトはホーム ディレクトリ) が表示されます。
- ユーザーに入力を求め、入力を取得します
- ユーザーの入力を「」で引数の配列に分割します
- 環境変数 PATH を「:」でトークンの配列に分割します。
ここからどう進めばいいのかわかりません。execv コマンドを使用する必要があることはわかっていますが、Google で調べたところ、理解できる例が見つかりませんでした。たとえば、コマンドが bin/ls の場合、execv はホーム ディレクトリにあるすべてのファイル/フォルダーが表示されることをどのようにして認識するのでしょうか?ディレクトリを変更したことをシステムに伝えるにはどうすればよいですか?
私はこのサイトをよく利用していますが、とても役に立ちました。 http://linuxgazette.net/111/ramankutty.html しかし、またしても私は困惑してしまいました。
ご協力いただきありがとうございます。私の既存のコードの一部を投稿する必要があるかどうか教えてください。ただし、それが必要かどうかはわかりませんでした。
解決
cd コマンドを実装するには、システム コールが必要です。 chdir
.
#include <unistd.h>
int chdir(
const char *path /* the path name */
);
したがって、次のように呼び出すことができます。
int ret1 = chdir("../foo/bar");
の戻り値 chdir
そのディレクトリに移動できた場合は 0、エラーが発生した場合は -1 です。このエラーについては、マニュアル ページを統合する必要があります。
現在のディレクトリはどのプログラムでも確認できるため、次のコマンドを実行すると ls
引数を指定しない場合、ls は実行中のディレクトリをチェックし、このディレクトリを唯一の引数として使用します。これは ls の機能であり、 execv
電話。
第二部については。
#include <unistd.h>
int execv(
const char *path, /* programm path*/
char *const argv[]/* argument vector*/
);
execv
指定された場所で実行可能ファイルを実行します path
そして、で与えられた引数を使用して、 argv
。したがって、実行したい場合は、 /bin/ls ../foo /bar
, 、次のようなものが必要です
char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
によって返されるエラー execv
は -1 です。コマンドが実行されなかった理由を知りたい場合は、マニュアルページを確認してください。
の NULL
で char *argv[] = {cmd_str, "../foo", "/bar", NULL };
の後に他の引数がないことを示すためにあります。 NULL
.
第三部。Unix ベースのシステムは通常、/ が含まれるコマンドを直接実行できるコマンドとして扱います。つまり、指定されたコマンド文字列にスラッシュが含まれているかどうかを最初に確認します。
int ret_value;
if (strchr(cmd_str, '/')
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
スラッシュがない場合は、次のすべてのディレクトリを参照する必要があります。 PATH
コマンドを実行できるかどうかを確認します。したがって、指定されたコマンドは次のとおりです ls ../foo /bar
の値を仮定してみましょう PATH
は ".:/sbin:/bin:/usr/bin"
。次に、最初に実行しようとします ./ls ../foo /bar
それから /usr/bin/ls ../foo /bar
そしてついに /bin/ls ../foo /bar
.
お役に立てれば。
他のヒント
たとえば、コマンドが次の場合
bin/ls
, 、 どうやってexecv
ホームディレクトリのすべてのファイル/フォルダーを表示することを知っていますか?ディレクトリを変更したことをシステムに伝えるにはどうすればよいですか?
すべてのプロセスには現在の作業ディレクトリがあり、次を使用して変更できます。 chdir
. 。子プロセスは親プロセスから作業ディレクトリを継承します。したがって、一般的にシェルは、次の要求に応じて現在の作業ディレクトリを管理します。 cd
ユーザーが入力したコマンド。組み込みではないコマンドが入力されると、 fork
子プロセスを作成して呼び出す execv
バイナリを実行するためにそこにあります。
取るのがアリなら PATH
ディレクトリ部分を含まないプログラム名を考慮して、可能なすべての組み合わせを試してください。 PATH
要素とプログラム名。指定したファイルが存在するかどうかを確認するか、単に実行して失敗した場合は次の処理に進むことができます。私は落ちる execv
通話が失敗しました。電話する必要があります _exit
子プロセスを終了するためです。
ほとんどのシェルは、 /
渡されるパスとして execv
直接。パスがそうでない場合は、 始める とともに /
, の場合、これは相対パスであり、オペレーティング システムは現在の作業ディレクトリを基準にしてそれを解決します。言い換えれば、 bin/ls
あなたの例からは、 ls
のバイナリ bin
ディレクトリは、現在の作業ディレクトリのサブディレクトリです。何も含まないコマンドのみ /
まったく、組み込みコマンドとして解釈されます (例: cd
)、または上にあるバイナリの名前 PATH
.
最初の引数は execv
は計算したとおりのパスです。の最初の要素 argv
list は伝統的に、入力されたときの名前と等しくなります。追加なしで PATH
ディレクトリ。最初の引数の後に、追加のコマンド ライン パラメーターが渡され、その後に NULL
リストを終了します。
問題はあなたがシェルがls
の作業を担当すると信じることです。ls
は、シェルの「部分」(この場合は少なくとも)ではありません。シェルは、ls
というプログラムを実行します。ほとんどのコメントは、ls
を見つける方法を説明しているようですが、それがあなたが混乱しているものであるとは思わない。
あなたがそれを書く前にシェルのポイントが何であるかを慎重に考えるべきです。コメントは、シェルが「単純に」という事実を「単純に」と呼ばれているという事実を指摘しており、それらのタスクを実行しないようにしてください。
ls
は、引数が与えられていない場合、getcwd
によって返される現在の作業ディレクトリのファイルを一覧表示することになっています。