쉘에서 명령 실행

쉘에서 명령 실행

tty터미널에서 명령을 실행할 때 반환됩니다 /dev/pts/10.

이 외에도 파일 /dev/stdout /dev/stdin/dev/stderr상호 작용이 터미널에 직접 표시됩니다.

user@laptop:build$ tty
/dev/pts/10
user@laptop:build$ echo "Test" > /dev/stdout
Test
user@laptop:build$ echo "Test" > /dev/stdin
Test
user@laptop:build$ echo "Test" > /dev/stderr
Test

또한 셸에서 시작된 모든 cli 애플리케이션은 stdout// 에 대한 파일 설명자를 엽니다 stderr. stdin즉, 무언가를 인쇄하는 스크립트를 실행하는 경우 인쇄는 쓰기와 동일합니다 stdout.

지금까지 stdout//는 쉘이 사용할 수 있는 유일한 인터페이스 stderr입니다 . stdin응용 프로그램의 경우에도 마찬가지입니다.

일부 운영 체제 구성 요소는 결국 기록된 데이터를 stdout터미널로 이동합니다. 그렇지 않으면 아무 것도 인쇄되지 않습니다.

stdout/stdin/stderrstd*터미널의 무언가와 실제로 상호 작용 하기 위해 터미널에 대한 연결은 언제 어디서 발생합니까 ?

내가 도전하고 싶은 대략적인 가정은 다음과 같습니다.

/dev/stdout, 실행 중인 쉘에 의해 생성 /dev/stdin되며 /dev/stderr, 쉘이 없으면 존재하지 않는 것입니다.

쉘은 터미널을 나타내는 실제 장치 파일을 통해 통신 채널을 설정하고 /dev/pts/10터미널 기능을 노출합니다. 이러한 방식으로 셸은 각 응용 프로그램이 간단한 인쇄를 위해 장치 파일을 처리하는 방법에 대해 걱정하지 않고 응용 프로그램에 간단한 파일 인터페이스를 제공합니다./dev/stdout/dev/stdin/dev/stderr

고쳐 쓰다

의사 터미널임에도 불구하고 /dev/pts/10의사 터미널의 개념을 도입하지 않고 답변을 제공하는 답변에 더 비중을 두겠습니다. 내 요점은 이것이 질문에 대한 대답을 방해할 뿐이라는 것입니다.

stdout/stdin/stderr/dev/std*터미널의 무언가와 실제로 상호 작용 하기 위해 터미널에 대한 연결은 언제 어디서 발생합니까 ?

답변1

/dev/pts/10노예의 끝은의사 단말 장치 쌍. 다른 쪽 끝에는 마스터 복제 장치를 열고 쌍으로 수신하는 프로그램이 있습니다 /dev/ptmx( /dev/pts/10열 때마다 /dev/ptmx다른 슬레이브 장치를 얻습니다). /dev/ptmx과 사이의 연결은 /dev/pts/10기본적으로 양방향 파이프입니다.반전이 있다.

터미널 에뮬레이터 애플리케이션을 열 때:

  • 그것은 열리고 /dev/ptmx다른 쪽 끝의 이름을 얻습니다. 반대쪽 끝을 구성하고 엽니다.
  • 그것은 포크,
  • 새로운 프로세스는 의사 터미널 장치의 다른 쪽 끝을 열고 연결합니다.표준 입력,표준 출력그리고표준 에러그것에,
  • 새 프로세스가 셸을 실행합니다.

쉘은 이 세 가지 파일 설명자를 설정하기 위해 아무 작업도 수행하지 않으며 상위 프로세스에서 상속합니다. 마찬가지로 해당 하위 프로세스는 셸에서 파일 설명자를 상속합니다.

논평: Linux 시스템에서 /dev/stdin/dev/stdout은 일련의 심볼릭 /dev/stderr링크로 가리키는 실제 파일이며 , 이는 실제 입력/출력 장치를 가리킵니다. 귀하의 경우에는 입니다 ./proc/<pid>/0/proc/<pid>/1/proc/<pid>/2/dev/pts/10

이 세 가지의 존재표준 스트림C 라이브러리에서 보장합니다.

편집하다: 업데이트된 질문을 해결하기 위해 답변의 몇 가지 요점을 명확히 하겠습니다.

  • 쓰여진 모든 것은 /proc/pts/*그것을 만든 터미널에서 읽고 표시되며 읽은 모든 것은 /proc/pts/*터미널에 연결된 입력 장치에서 나옵니다.
  • Linux에서는 /dev/stdout일반적으로 에 심볼릭 링크되어 /proc/self/fd/1있고 에 /dev/stdin심볼릭 링크되어 있습니다 /proc/self/fd/0. 가상 /proc파일 시스템은 응용 프로그램 프로세스 ID가 있는 각 응용 프로그램에 대한 /proc/self심볼릭 링크를 신중하게 표시합니다./proc/<pid><pid>
  • /proc/<pid>/fd기호 링크는 응용 프로그램이 상위 응용 프로그램에서 열거나 상속하는 파일, 파이프 및 기타 콘텐츠를 가리킵니다 . 각 애플리케이션은 0입력 읽기, 1출력 쓰기, 2오류 쓰기 등 세 가지 파일 설명자를 열도록 보장됩니다 . 당신에 관한 한 그렇습니다 /dev/pts/10.

출력을 다른 파일로 리디렉션하지 않고 쉘에서 실행되는 모든 명령이 터미널에 기록됩니다. 이 규칙의 예외는 명령이 다음과 같은 경우입니다.프로세스 그룹전망과는 다르다프로세스 그룹터미널에 대한 쓰기가 실패하고 SIGTTOU명령으로 전송됩니다. stty tostop이 동작을 사용하고 제어할 수 있습니다 stty -tostop.

stty tostop
echo "/dev/stdout points to the terminal, but I won't print anything" &
stty -tostop
echo "You can see me" &

답변2

POSIX 호환 프로그램은 상위 프로세스로부터 파일 설명자 #0, #1 및 #2(각각 프로그래밍 상수 stdin및 # stdout2라고도 함) 를 상속받을 것으로 예상할 수 있습니다.stderr개봉하여 사용 가능.

가장 간단한 경우, 텍스트 콘솔에 로그인된 세션 내의 명령줄 프로그램에서 리디렉션이 적용되지 않으면 이 상속 체인은 로그인 getty된 사용자에 대해 TTY 장치를 초기화한 프로세스 로 다시 돌아갑니다. 세션.

GUI를 사용하여 로그인할 때 디스플레이 관리자 프로세스( gdm/kdm/sddm/lightdm/xdm/<whatever>dm)는 일반적으로 표준 입력 및 출력을 세션의 첫 번째 프로세스와 유사하게 설정하며 /dev/null이러한 $HOME/.xsession-errors파일 설명자도 세션에서 시작된 모든 GUI 프로그램에 상속됩니다. 데스크탑 환경의 일부이거나 데스크탑 메뉴 또는 아이콘을 사용하여 실행됩니다.

예를 들어 SSH 세션의 경우 sshd세션을 초기화하기 위해 분기된 프로세스는 의사 TTY 장치 쌍을 할당하고 파일 설명자가 stdin/out/err그 중 절반을 가리킨 다음 exec()사용자의 셸을 편집합니다. 분기의 다른 쪽 끝은 의사 TTY 장치 쌍의 나머지 절반을 보유하고 세션이 종료될 때까지 네트워크와 의사 TTY 장치 간의 발신/수신 트래픽에 대한 암호화/암호 해독을 처리합니다.

터미널 에뮬레이터가 GUI 세션에서 시작되면 새 세션을 초기화할 때와 거의 같은 방식으로 동작합니다 sshd. 즉, 의사 TTY fork()자체를 할당하고 파일 설명자에 대한 지점을 포함하여 세션 복사본을 설정합니다. 0, #1, #2를 가상 TTY로, 마지막으로 exec()사용자 셸에서 포크의 반대쪽은 터미널 창의 시각적 표현을 실제로 유지하는 작업을 계속 처리합니다.

간단히 말해서, (의사?) TTY 장치는 터미널 세션을 초기화하는 것을 통해 stdin/stdout/stderr에 연결되며, 해당 장치와 애플리케이션 사이에 존재할 수 있는 모든 프로세스는 체인으로 전달됩니다. 상속받은 사람아무것도하지 마세요이러한 파일 설명자를 그대로 하위 프로세스에 전달하도록 하세요.

리디렉션 연산자가 셸 명령줄에서 사용되면 셸은 실제로 명령을 실행 fork()하기 위한 준비 과정에서 자신의 임시 복사본을 생성하므로 임시 복사본은 해당 파일 설명자를 닫고 그 자리에 리디렉션 연산자를 엽니다. 수정된 stdin/out/err 파일 설명자를 상속하도록 명령을 사용합니다 .exec()fork()exec()


일부 Unix 스타일 시스템에서는 /dev/std*장치가 셸에서 처리될 수 있습니다. 그러나 Linux는 이를 더욱 "현실적"으로 만듭니다.

Linux에서 , /dev/stdin/dev/stdout는 파일 시스템을 가리키는 /dev/stderr평범한 오래된 기호 링크입니다 ./proc

$ ls -l /dev/std*
lrwxrwxrwx 1 root root 15 Feb  4 08:22 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Feb  4 08:22 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Feb  4 08:22 /dev/stdout -> /proc/self/fd/1

udev이러한 링크는 시스템 시작 시 RAM 기반 파일 시스템이 초기화될 때 생성됩니다. /dev그것들은 단지 평범한 기호 링크일 뿐이며 마법적인 것은 아닙니다.

그러나 이는 /proc시스템의 프로세스 상태를 실시간으로 반영할 수 있는 완전한 가상 파일 시스템이므로 몇 가지 "마법의" 속성을 가지고 있습니다.

  • /proc/self/proc/<PID>디렉토리에 대한 심볼릭 링크입니다진행 상황 보기:
$ ls -l /proc/self   # the PID of this ls command will be 10839
lrwxrwxrwx 1 root root 0 Feb  4 08:22 /proc/self -> 10839/

$ ls -l /proc/self   # the PID of this ls command will be 10843
lrwxrwxrwx 1 root root 0 Feb  4 08:22 /proc/self -> 10843/
  • /proc/<PID>/fd<PID>프로세스에서 사용하는 열린 파일 설명자 와 이름이 일치하는 기호 링크가 포함된 디렉토리입니다 .이 파일 설명자와 관련된 모든 항목을 가리킵니다..

따라서 프로세스가 /dev/pts/10액세스를 시도 하면 /dev/stdin심볼릭 링크는 /proc/self/fd/0... 을 가리키고 /proc/self/fd/0액세스 되면 /proc파일 시스템 드라이버는 커널의 프로세스 테이블을 보고 이를 사용하여 액세스하는 프로세스의 파일 설명자 테이블을 찾습니다. 심볼릭 링크 /proc/self/fd/0로 렌더링/dev/pts/10으니까프로세스는 현재 /dev/pts/10파일 설명자 #0과 연결되어 있습니다.

Solaris 11에서 장치는 "마법"이기도 한 /dev/std*디렉토리에 대한 심볼릭 링크입니다 ./dev/fd/

$ uname -sr
SunOS 5.11
$ ls -l /dev/std*
lrwxrwxrwx   1 root     root           0 Jun 17  2019 /dev/stderr -> ./fd/2
lrwxrwxrwx   1 root     root           0 Jun 17  2019 /dev/stdin -> ./fd/0
lrwxrwxrwx   1 root     root           0 Jun 17  2019 /dev/stdout -> ./fd/1

여기에서 Solaris 파일 시스템 드라이버는 역사적인 이유로 Linux처럼 파일 시스템으로 리디렉션하는 /dev대신 디렉터리의 장치 노드를 사용하여 마술을 수행합니다 ./dev/fd/proc

답변3

쉘에서 명령 실행

이는 명령이 셸에서 실행될 때 발생합니다.

  • 셸 호출 fork: 셸이 두 프로세스에서 실행되는 방식입니다.
  • 새로운 쉘 설정 std in/out/err: 그러나 리디렉션이 없으면 아무 작업도 수행되지 않습니다. 새 프로세스는 원래 셸에서 이러한 값을 상속하며 셸에는 이미 올바른 값이 있습니다.
  • 새 쉘 호출은 exec새 프로그램을 실행합니다. 이 새 프로그램은 값을 상속 std in/out/err하고 새 쉘을 대체합니다.

이 새로운 셸은 매우 일시적입니다(단지 구현 세부 사항이므로 현재 문서에 언급되어 있습니다). 서브쉘과는 다릅니다.

새 명령이 열립니다/dev/stdin

새 프로그램이 열리면 /dev/stdin커널의 파일 시스템 코드는 이것이 자신을 가리키는 심볼릭 링크임을 확인 하고 nnnn이 프로세스 pid인 곳을 가리키는 심볼릭 링크임을 /proc/self/fd/0알게 됩니다 . /dev/self예를 들어 파일을 가리키는 파일입니다. 열면 새 파일 설명자가 생성됩니다. 파일 설명자 0이 이미 파일을 가리키고 있으므로 일반적인 상황에서는 열 필요가 없습니다./proc/nnnn/proc/nnnn/fd/0/dev/pts/10/dev/stdindev/stdin

(이것은 프로그램이 stdin을 읽도록 작성되지 않았지만 파일에서 읽을 수 있는 경우에만 필요합니다.) (이 모든 것은 stdout 및 stderr에도 적용됩니다.)

의 파일은 /proc실제 파일이 아닙니다(어디에도 저장되지 않음). 파일 시스템에서 액세스할 때 동적으로 생성됩니다(디스크에 기록되지 않음). 이는 디스크가 아닌 커널에서 데이터 구조를 가져옵니다.

관련 정보