web-dev-qa-db-ja.com

stdoutおよびstdinファイル記述子を閉じた後に再度開く

引数を指定すると、stdoutをファイルにリダイレクトするか、ファイルからstdinを読み取る関数を作成しています。これを行うには、stdoutまたはstdinに関連付けられたファイル記述子を閉じます。これにより、ファイルを開いたときに、閉じたばかりの記述子の下で開きます。これは機能しますが、問題は、これが完了したら、stdoutとstdinを本来の状態に戻す必要があることです。

Stdoutでできることはopen( "/ dev/tty"、O_WRONLY)です。しかし、これがなぜ機能するのかはわかりません。さらに重要なことは、stdinの同等のステートメントを知らないことです。

だから、私は、標準出力のために

close(1);
if (creat(filePath, O_RDWR) == -1)
{
    exit(1);
}

および標準入力用

close(0);
if (open(filePath, O_RDONLY) == -1)
{
    exit(1);
}
30
RegisteredUser

ファイル記述子を複製するには、dup()およびdup2()を使用する必要があります。

int stdin_copy = dup(0);
int stdout_copy = dup(1);
close(0);
close(1);

int file1 = open(...);
int file2 = open(...);

< do your work. file1 and file2 must be 0 and 1, because open always returns lowest unused fd >

close(file1);
close(file2);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);

ただし、注意が必要な場合があります(man dupより):

2つの記述子は、ファイル記述子フラグ(close-on-execflag)を共有しません。複製記述子の実行時終了フラグ(FD_CLOEXEC。fcntl(2)を参照)はオフです。

これが問題になる場合は、競合状態を回避するために、dup2()の代わりにdup3()を使用して、close-on-execフラグを復元する必要があります。

また、プログラムがマルチスレッドの場合、他のスレッドが再マップされたstdin/stdoutに誤って書き込み/読み取りを行う可能性があることに注意してください。

40
Ambroz Bizjak

記述子を「保存」できると思いますリダイレクト前

int save_in, save_out;

save_in = dup(STDIN_FILENO);
save_out = dup(STDOUT_FILENO);

後でdup2を使用してそれらを復元できます。

/* Time passes, STDIN_FILENO isn't what it used to be. */
dup2(save_in, STDIN_FILENO);

その例ではエラーチェックを行っていません。

17
cnicutar

子プロセスを作成し、子の内部でのみリダイレクトを設定できます。次に、子プロセスが終了するのを待ち、親プロセスでの作業を続けます。そうすれば、リダイレクトを逆にすることをまったく心配する必要はありません。

Fork()およびwait()を使用するコードの例を探してください。

1
reed_do_it