web-dev-qa-db-ja.com

dup2 / dup-ファイル記述子を複製する必要があるのはなぜですか?

dup2dupの使用を理解しようとしています。

Manページから:

DESCRIPTION

dup and dup2 create a copy of the file descriptor oldfd.
After successful return of dup or dup2, the old and new descriptors may
be used interchangeably. They share locks, file position pointers and
flags; for example, if the file position is modified by using lseek on
one of the descriptors, the position is also changed for the other.

The two descriptors do not share the close-on-exec flag, however.

dup uses the lowest-numbered unused descriptor for the new descriptor.

dup2 makes newfd be the copy of oldfd, closing newfd first if necessary.  

RETURN VALUE

dup and dup2 return the new descriptor, or -1 if an error occurred 
(in which case, errno is set appropriately).  

なぜそのシステムコールが必要なのですか?ファイル記述子の複製の使用は何ですか?

ファイル記述子がある場合、なぜそのコピーを作成したいのですか?

dup2/dupが必要な例を説明し、例を挙げていただければ幸いです。

ありがとう

74
JAN

Dupシステムコールは、既存のファイル記述子を複製し、同じ基になるI/Oオブジェクトを参照する新しい記述子を返します。

Dupを使用すると、シェルで次のようなコマンドを実装できます。

ls existing-file non-existing-file > tmp1  2>&1

2>&1は、シェルに、記述子1の複製であるファイル記述子2をコマンドに与えるように指示します(つまり、stderrとstdoutは同じfdを指します)。
今すぐls on 存在しないファイルを呼び出すためのエラーメッセージとls on existing filetmp1ファイルに表示されます。

次のコード例は、パイプの読み取り側に接続された標準入力でプログラムwcを実行します。

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
    close(STDIN); //CHILD CLOSING stdin
    dup(p[STDIN]); // copies the fd of read end of pipe into its fd i.e 0 (STDIN)
    close(p[STDIN]);
    close(p[STDOUT]);
    exec("/bin/wc", argv);
} else {
    write(p[STDOUT], "hello world\n", 12);
    close(p[STDIN]);
    close(p[STDOUT]);
}

子は、読み取り終了をファイル記述子0に複製し、pのファイル記述子を閉じ、wcを実行します。 wcが標準入力から読み取る場合、パイプから読み取ります。
これは、dupを使用してパイプを実装する方法です。dupを使用すると、パイプを使用して別の何かを作成できます。これは、システムコールの美しさです。ツールは、他の何かを使用して順番に構築されました。最後に、システムコールは、カーネルで取得する最も基本的なツールです。

乾杯:)

39
Deepthought

ファイル記述子を複製するもう1つの理由は、fdopenで使用することです。 fcloseは、fdopenに渡されたファイル記述子を閉じます。そのため、元のファイル記述子を閉じたくない場合は、最初にdupで複製する必要があります。

16
R..

Dup/dup2に関連するいくつかの点に注意してください

dup/dup2-技術的には、異なるハンドルで単一プロセス内で1つのファイルテーブルエントリを共有することが目的です。 (フォークしている場合、記述子はデフォルトで子プロセスで複製され、ファイルテーブルエントリも共有されます)。

つまり、dup/dup2関数を使用して、1つの単一の開いているファイルテーブルエントリに対しておそらく異なる属性を持つ複数のファイル記述子を持つことができます。

(現時点では、FD_CLOEXECフラグのみがファイル記述子の唯一の属性であるように思われます)。

http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html

dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0);

dup2(fildes, fildes2); is equivalent to 

   close(fildes2);
   fcntl(fildes, F_DUPFD, fildes2);

違いは(最後の)-2つの関数呼び出しが関与するため、dup2とfcntl closeの後にfcntlが続くいくつかのerrno値を除き、競合状態が発生する可能性があります。

詳細は http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html から確認できます。

使用例-

シェルでジョブ制御を実装する際の1つの興味深い例で、dup/dup2の使用は以下のリンクで見ることができます。

http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs

dupは、プロセスからの出力をリダイレクトできるようにするために使用されます。

たとえば、プロセスからの出力を保存する場合は、出力を複製し(fd = 1)、複製したfdをファイルにリダイレクトし、プロセスをフォークして実行し、プロセスが終了したら、再度リダイレクトしますfdを出力に保存しました。

4
alinsoar