stdout fd를 '읽기' 시스템 호출에 전달하지만 여전히 잘 작동합니다.

stdout fd를 '읽기' 시스템 호출에 전달하지만 여전히 잘 작동합니다.

1(stdout)/ 2(stderr)을 시스템 호출에 전달했지만 read여전히 잘 작동합니다. 그런 다음 0(stdin)을 시스템 호출에 전달 write하고 그것이 작동하는지 확인합니다!

int main(int argc, char** argv){
    char buf[1024] = "abcdefghi\n";

    write(0, buf, 10);

    char readbuf[1024] = {0};
    // read(1, readbuf, 10); works too
    read(2, readbuf, 10);
    write(2, readbuf, 10);

    return 0;
}

산출:

abcdefghi
hey stdin  <-- I input this
hey stdin

혼란스러워서 오류라고 생각했습니다.

실험:

그런 다음 fd 2를 리디렉션하려고 시도했습니다.

$ ./a.out 2>/dev/null

이번에는 읽기와 두 번째 쓰기가 모두 '표시'되지 않습니다. 출력은 다음과 같습니다

abcdefgi

그렇다면 stderr을 읽기에 사용할 수 있습니까?

그런 다음 stdout 및 stderr을 닫고 stdin의 복사본 두 개를 만듭니다.

int main(int argc, char** argv){
    char buf[1024] = "abcdefghi\n";

    close(1);
    close(2);

    dup2(0, 1);
    dup2(0, 2);

    write(0, buf, 10);

    char redbuf[1024] = {0};
    read(2, redbuf, 10);
    write(2, redbuf, 10);

    return 0;
}

다시 작동합니다.

산출:

abcdefghi
hey stdin  <-- I input this
hey stdin

그렇다면 stdin을 쓰기에 사용할 수 있습니까?

여기에 설명이 필요합니다.

질문

나는 알고 싶다:

stdout/stderr을 읽기에 사용할 수 있는 이유는 무엇입니까?

왜 stdin을 쓰기에 사용할 수 있나요?

세 개의 스트림(표준 입력, 표준 출력, 표준 오류) 내부적으로하나개울 ?

그렇지 않다면 왜 이런 결과가 나오는 걸까요?

답변1

입력/출력/오류에 fd 0/1/2를 사용하는 것이 유일한 관례입니다. 리디렉션 없이 프로그램을 호출하면 세 가지 모두 tty를 참조하고 tty는 읽기 및 쓰기 액세스로 열립니다. 즉, 원하는 대로 읽거나 쓸 수 있습니다. 표현식 스트림은 FILEC나 streamC++와 같은 더 높은 수준의 I/O에 자주 사용되지만 동일한 스트림이라고 부를 수 있습니다.

이것이 리디렉션되거나 리디렉션되지 않은 예제 모두 입력한 텍스트를 에코하는 이유입니다.

반면에 리디렉션을 수행하면 셸은 읽기 전용 또는 쓰기 전용 액세스로 파일을 엽니다. 귀하의 예에서는 ./a.out 2>/dev/null쓰기 대상이 0리디렉션되지 않아 터미널에 계속 연결되어 화면에 표시됩니다. 읽기는 2쓰기에만 연결되어 있으므로 /dev/null실패해야 하지만 프로그램과의 차이점을 눈치채지 못할 것입니다. 에 쓰기가 2성공했지만 에 기록되었습니다 /dev/null. 잘못된 읽기 및 유효한 쓰기는 /dev/null터미널에 표시되지 않습니다.

답변2

stdin/stdout/stderr를 리디렉션하지 않는 한 이러한 파일 설명자는 로그인 절차에 의해 열렸으며 tty읽기 및 쓰기 관련 파일을 첫 번째 파일로 열고(결과적으로 파일 설명자 #0이 됨) 나중에 dup()가져오기 위해 2번 호출합니다. stdout 및 stderr에 대한 파일 설명자.

에서 언급했듯이사용자로부터 명령을 읽을 수 있으면서 `less`는 어떻게 stdin에서 데이터를 가져오나요?이전에는(이전에는 /dev/tty에 도입됨 UNIX) 프로그램에서 확인을 요청할 때 more읽었습니다 .stderr

관련 정보