C에서 다른 파일 설명자에 쓸 수 있습니까?

C에서 다른 파일 설명자에 쓸 수 있습니까?

모든 표준 출력을 파일로 리디렉션하려면 다음을 실행합니다.

my_prog 1> out

stderr로 동일한 작업을 수행하려면 다음을 실행합니다.

my_prog 2> err

그러나 나는 쉘에 다른 파일 설명자가 있다는 것을 알고 있습니다. 예를 들어, 상위 답변이 문제세 번째 파일 설명자를 사용하면 명령줄을 통해 데이터를 보낼 수 있습니다.

echo "Some console message" 1>&3

C 프로그램이 이 파일 설명자에 쓸 수 있는 방법이 있습니까? 다른 프로그램에서 읽지 않고 쓰기만 하면 출력이 터미널로 전송됩니까?

답변1

몇 가지 사항을 명확히하기 위해. 존재하다:

echo foo >&3

echo"foo\n"파일 설명자 3 에는 쓰지 않습니다 . echo항상 파일 설명자 1인 stdout에 씁니다. write()첫 번째 인수로 정수, 두 번째 인수로 시작하는 메모리 영역에 대한 포인터1 및 ( ) 길이를 사용하여 시스템 호출을 호출합니다. 세 번째로.foo\n4foo\n

C언어에서는 이렇게 쓸 수 있습니다 write(1, "foo\n", 4). 위 코드에서 쉘은 fd 1을 동일한 코드로 리디렉션합니다.파일 설명 열기echo(시스템 호출을 통해 ) 호출하기 전에 fd 3을 엽니다 dup2(). 따라서 기능적으로는 동일하지만 do 와 동일하지는 않습니다 write(3, "foo\n", 4). 실제로는 (단순화) 다음과 같습니다.

if (pid = fork())
  waitpid(pid, ...);
else {
  dup2(3, 1);
  execlp("echo", "foo", 0);
} 

그리고 echo만들었어요write(1, "foo\n", 4)

거의 모든 쉘을 제외하면 이 내장되어 있으므로 또는 이 echo없습니다 . 대신 셸은 다음을 수행합니다.forkexec

saved_stdout = dup(1);
dup2(3, 1);
builtin_echo("foo");
dup2(saved_stdout, 1); close(saved_stdout); /* restore stdout */

( 동일한 프로세스에서 builtin_echo()이 작업을 수행하는 함수는 어디에 있습니까?)write(1, "foo\n", 4)

이를 수행하는 명령에 대해서는 / 에 대한 내장 명령을 write(3, "foo\n", 4)볼 수 있습니다 .kshzshprint -u3 foo

이제 각 프로세스에는 파일 설명자가 있습니다. 0, 1, 2를 제외하고는 규칙에 따라 stdin, stdout 및 stderr용으로 예약되어 있습니다. 다른 fd는 일반적으로 특별하지 않지만 쉘(응용 프로그램의 한 유형일 뿐임)에서는 fd 0에서 <some-value>값이 9 이상인 특정 위치까지 (쉘의) 사용자가 사용하도록 예약되어 있습니다. 껍질은 그 안에 수프를 넣기 위해 섞이지 않습니다. 예를 들어 saved_stdout = dup(1)위의 내 것은 근사치입니다. 실제로 쉘은 saved_stdout값이 <some-value>.

이제 fd에 0, 1, 2 이외의 규칙이 첨부되어 있지 않으므로 fd 3에서는 아무 것도 열 수 없습니다. 아마도 닫혀있을 것입니다. 또는 그렇지 않은 경우 스크립트 호출자는 O_CLOEXCfd 3에서 아무 것도 열릴 것이라고 기대하지 않기 때문에 스크립트를 열어줄 이유가 없기 때문에 스크립트를 닫는 것(또는 플래그를 추가하는 것)을 잊어버렸을 수도 있습니다.

fd 3에 무언가가 열려 있다는 것을 알고 있다면(일반적으로 동일한 스크립트에서 미리 사용자가) fd 3을 사용할 수 있습니다. 예를 들면 다음과 같습니다.

 {
   var=$(cmd 2>&1 >&3)
 } 3>&1

dup()여기서 fd 3은 fd 1의 a 로 정의됩니다 .앞으로이것을 사용하여 fd 1로 cmd돌아갑니다 .dup()

답변2

설명자가 열려 있다고 가정하면 C는 설명자 에 액세스할 수 있습니다 write(또는 궁극적으로 로 귀결되는 일부 상위 수준 호출을 사용할 가능성이 더 높음 ). write(2)여기 이게 있어요write2three.c

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    if ((fd = dup(3)) == -1) err(1, "dup failed");
    dprintf(fd, "hello\n");
    exit(EXIT_SUCCESS);
}

예를 들어

$ make write2three  
cc     write2three.c   -o write2three
$ ./write2three
write2three: dup failed: Bad file descriptor
$ rm out
$ ./write2three 3>out
$ cat out
hello
$ 

나중에 쉘에서 정리해야 할 수도 있습니다.

$ exec 3>&-
$ 

답변3

저는 C에 익숙하지 않아서 더 좋은 방법이 있을 수도 있지만 간단하게 시스템 호출( man 2 write)을 사용하면 됩니다.

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

쓰기 데이터가 전송되는 위치는 열려 있는 파일 설명자에 따라 다릅니다. 파일 설명자가 터미널에 속하는 경우에만 데이터가 터미널에 도달합니다.

파이프나 소켓에 쓰고 다른 쪽 끝이 데이터를 읽지 않는 경우 write()버퍼가 가득 차면 쓰기 응용 프로그램(예: 호출)이 차단됩니다.

파일 설명자를 볼 수 있습니다./proc/$PID/fd

답변4

C에서 다른 파일 설명자에 쓸 수 있습니까?

예.

대부분의 프로세스는 이를 실행하는 상위 프로세스로부터 3개의 열린 파일 설명자를 상속받습니다.

stdin, stdout그리고 stderr. 이는 각각 파일 설명자 0 - 2입니다.

나는 fd 0( stdin)이 읽기 전용 모드로 열려 있다고 생각하므로 C 프로그램은 이 파일 설명자를 읽을 수 있지만 쓸 수는 없습니다.

프로그램이 다른 파일을 열면 증분 순서로 다음 파일 설명자를 가져옵니다.

관련 정보