리디렉션/파이프를 사용할 때 bash는 실제로 stdin/stdout/stderr를 어떻게 변경합니까?

리디렉션/파이프를 사용할 때 bash는 실제로 stdin/stdout/stderr를 어떻게 변경합니까?

불행하게도 내가 찾은 것은 단지 리디렉션의 구문이거나 리디렉션이 작동하는 방식에 대한 피상적인 정보뿐이었기 때문에 이것을 알아낼 행운이 없었습니다.

내가 알고 싶은 것은 파이프나 리디렉션을 사용할 때 bash가 실제로 어떻게 변하는가입니다 stdin. 예를 들어 다음을 실행하는 경우:stdoutstderr

ls -la > diroutput.log

stdout로 어떻게 바뀌 나요 ls?diroutput.log

나는 이것이 다음과 같이 작동한다고 생각합니다.

  • Bash가 실행되어 fork(2)자체 복사본을 생성합니다.
  • bash 프로세스를 포크하고 다음 과 같은 것을 사용 stdout하도록 설정하십시오 .diroutput.logfreopen(3)
  • 분기된 bash 프로세스가 실행되거나 execve(2)유사한 exec 기능이 자체적으로 교체되어 ls이제 stdoutbash 설정을 사용합니다.

그러나 그것은 단지 내 경험에 근거한 추측일 뿐입니다.

답변1

strace -f나는 이 문제를 해결하기 위해 C를 사용하고 간단한 개념 증명을 작성할 수 있었습니다 .

execve내 생각대로 bash는 호출하기 전에 하위 프로세스의 파일 설명자를 조작하는 것 같습니다 .

작동 원리는 ls -la > diroutput.log대략 다음과 같습니다.

  • 배시 통화fork(2)
  • 분기된 bash 프로세스는 출력 리디렉션을 확인 diroutput.log하고 open(2).
  • 포크된 bash 프로세스는 파일 설명자를 시스템 호출 stdout로 대체합니다.dup2(2)
  • execve(2)bash는 이를 대체하는 실행 가능 이미지를 호출 ls한 다음 이미 설정된 이미지를 상속합니다 .stdout

관련 시스템 호출은 다음과 같습니다( strace출력).

6924  open("diroutput.log", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 
6924  dup2(3, 1)                        = 1 
6924  close(3)                          = 0 
6924  execve("/bin/ls", ["ls", "-la"], [/* 77 vars */]) = 0

관련 정보