4

私はCで独自のシェルを作成しています。ユーザーの現在のディレクトリを表示し、フルパスに基づいてコマンドを実行し(execvを使用する必要があります)、ユーザーがcdでディレクトリを変更できるようにする必要があります。

これは宿題です。先生は私たちにCの基本的な入門書と、プログラムがどのように機能するかについての非常に簡単な骨組みだけを教えてくれました。私は簡単に諦める人ではないので、これを行う方法を3日間研究してきましたが、今は困惑しています。

これは私がこれまでに持っているものです:

  • ユーザーのユーザー名、コンピューター名、および現在のディレクトリ(デフォルトはホームディレクトリ)を表示します。
  • ユーザーに入力を求め、入力を取得します
  • ユーザーの入力を「」で引数の配列に分割します
  • 環境変数PATHを「:」でトークンの配列に分割します

ここから先に進む方法がわかりません。execvコマンドを使用する必要があることはわかっていますが、Googleでの調査では、理解できる例は実際には見つかりませんでした。たとえば、コマンドがbin / lsの場合、execvはホームディレクトリからすべてのファイル/フォルダを表示することをどのようにして知るのでしょうか。ディレクトリを変更したことをシステムに伝えるにはどうすればよいですか?

私はこのサイトをたくさん使ってきました。http://linuxgazette.net/111/ramankutty.htmlですが、やはり困惑しています。

ご協力いただきありがとうございます。既存のコードの一部を投稿する必要があるかどうかを教えてください。ただし、それが必要かどうかはわかりません。

4

4 に答える 4

1

cd コマンドを実装するには、システム コールが必要ですchdir

#include <unistd.h>

int chdir(
    const char *path /* the path name */
);

したがって、次のように呼び出すことができます。

int ret1 = chdir("../foo/bar");

の戻り値は、chdirそのディレクトリに移動できた場合は 0、エラーが発生した場合は -1 です。エラーについては、man ページを統合する必要があります。

現在のディレクトリはどのプログラムでも確認できるため、ls引数を指定せずに実行すると、ls は実行中のディレクトリを確認し、このディレクトリを唯一の引数として使用します。これは ls の機能であり、execvcall の機能ではありません。

第二部。

#include <unistd.h>
int execv(
     const char *path, /* programm path*/
     char *const argv[]/* argument vector*/
);

execvpathは、指定された場所で、 で指定された引数を使用して実行可能ファイルを実行します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 です。コマンドが実行されなかった理由を知りたい場合は、man ページを参照してください。

NULLinは、の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を調べて、コマンドを実行できるかどうかを確認する必要があります。したがって、指定されたコマンドは isであり、 isls ../foo /barの値を仮定します。次に、最初にthenを実行し、最後に を実行しようとします。PATH".:/sbin:/bin:/usr/bin"./ls ../foo /bar/usr/bin/ls ../foo /bar/bin/ls ../foo /bar

お役に立てれば。

于 2012-09-29T10:37:02.980 に答える
1

たとえば、コマンドが の場合、ホーム ディレクトリからすべてのファイル/フォルダを表示するbin/lsにはどうすればよいでしょうか? execvディレクトリを変更したことをシステムに伝えるにはどうすればよいですか?

すべてのプロセスには現在の作業ディレクトリがあり、 を使用して変更できますchdir。子プロセスは、親プロセスから作業ディレクトリを継承します。したがって、一般に、シェルはcd、ユーザーが入力したコマンドに応答して、現在の作業ディレクトリを管理します。組み込みではないコマンドが入力されるとfork、子プロセスを作成し、execvそこを呼び出してバイナリを実行します。

PATHディレクトリ部分を含まないプログラム名を考慮したくない場合は、要素とプログラム名の可能なすべての組み合わせを試す必要がありますPATH。指定されたファイルが存在するかどうかを確認するか、単純に実行を試みて、失敗した場合は次のファイルに進むことができます。すべてのexecv呼び出しが失敗した場合は_exit、子プロセスを終了するために呼び出す必要があります。

ほとんどのシェルは、直接/渡されるパスとして aを含むコマンドを処理することに注意してください。パスが で始まらexecvない場合、それは相対パスであり、オペレーティング システムは現在の作業ディレクトリに対してパスを解決します。つまり、あなたの例の は、現在の作業ディレクトリのサブディレクトリであるディレクトリ内のバイナリを参照します。何も含まないコマンドのみが組み込みコマンド ( など) として解釈されるか、./bin/lslsbin/cdPATH

への最初の引数execvは、計算したパスです。リストの最初の要素は、argv伝統的に、入力されたままの名前と同じです。つまり、PATHディレクトリが追加されていません。その最初の引数の後に、追加のコマンド ライン パラメータが渡され、その後NULLにリストを終了する a が続きます。

于 2012-09-29T09:35:54.677 に答える
1

ls引数が与えられていない場合、現在の作業ディレクトリ内のファイルをリストすることになっていることを、それ自体が知っています。getcwd

于 2012-09-29T10:52:53.257 に答える