내 말이 맞습니까? 키보드의 모든 입력은제어 터미널? 이는 프로그램이 제어 터미널 없이 실행되면 사용자 입력을 받을 수 없음을 의미합니다. 이것이 Linux의 모든 프로그램에 적용됩니까?
업데이트 #1: 질문을 명확히하기 위해 내 Python 호출기 모듈표준 입력 리디렉션 시 충돌 발생:
$ ./pager.py < README.rst
...
File "pager.py", line 566, in <module>
page(sys.stdin)
File "pager.py", line 375, in page
if pagecallback(pagenum) == False:
File "pager.py", line 319, in prompt
if getch() in [ESC_, CTRL_C_, 'q', 'Q']:
File "pager.py", line 222, in _getch_unix
old_settings = termios.tcgetattr(fd)
termios.error: (25, 'Inappropriate ioctl for device')
이는 키보드 입력을 로 설정하기 위해 설명자를 가져오려고 하기 때문입니다 fd = sys.stdin.fileno()
. 리디렉션 후 stdin
해당 파일 설명자는 더 이상 키보드 입력과 연결되지 않으므로 설정하려고 하면 input-output control
오류가 발생합니다.
이거 얻으라고 했는데 controlling terminal
어디서 나온건지 모르겠네요. 사용자로부터 실행 중인 프로세스로 신호를 보내는 것이 일종의 채널이라는 것을 알고 있지만 동시에 신호 없이도 프로세스를 실행할 수 있습니다.
그래서 질문은 - 항상 키보드 입력을 읽어야 합니까 controlling terminal
? 호출기 프로세스가 호출기 프로세스 없이 실행되면 어떻게 됩니까? 키보드 입력이 여전히 사용자에게 중요합니까? 다른 소스에서 가져와야 하나요?
답변1
습관. 터미널 애플리케이션은 사용 중인 키보드 터미널에 해당하는 장치 파일(Linux의 경우 직렬 장치, 의사 터미널 장치의 경우 ... /dev/ttyS0
과 같은 파일)에서 키보드 입력을 읽습니다./dev/ttyUSB0
/dev/pts/0
장치가 반드시 필요한 것은 아닙니다.제어 터미널프로세스(또는 해당 문제에 대한 모든 프로세스).
장치 파일에 대한 읽기 권한이 있고 cat /dev/pts/x
상대방 터미널에 입력된 내용(있는 경우)을 읽을 수 있는 한 이 작업을 수행할 수 있습니다.
실제로, 프로세스를 제어하는 터미널이고 해당 프로세스가 해당 터미널의 포그라운드 프로세스 그룹에 있지 않은 경우 프로세스는 일반적으로 프로세스에서 데이터를 읽으려고 시도하는 동안 중단됩니다(포그라운드 프로세스 그룹에 있었다면 프로세스는 중단됩니다). 정지되었을 것입니다). ^C
// 보내면 ^Z
프로세스가 터미널 장치에서 데이터를 읽는지 여부에 관계없이 SIGINT/SIGTSTP/SIGQUIT를 받게 됩니다. ^\
최종 장치가 최종 장치가 아니면 이런 일은 일어나지 않을 것입니다.제어 터미널프로세스 이름(프로세스가 다른 세션의 일부인 경우) 그게 다야제어 터미널그것은 관하여. 이것은직업 통제대화형 쉘로 구현된 메커니즘. SIGTTIN/SIGTTOU 및 SIGINT/SIGTSTP/SIGQUIT 신호 외에도 제어 터미널은 터미널이 hup을 정지할 때 SIGHUP 전송에 참여합니다. 이는 또한 /dev/tty
리디렉션되는 tty 장치이기도 합니다.
어쨌든 이것은 터미널 입력에만 작동합니다. 직렬 케이블을 통해 연결된 터미널 장치처럼 실제로 작동하거나, X11 터미널 에뮬레이터처럼 에뮬레이트되거나(예: xterm
의사 터미널 장치 사용), Linux 대화형 프로세스가 있는 가상 터미널처럼 커널에 의해 에뮬레이션됩니다. /dev/tty<x>
(그리고 표준 터미널 인터페이스보다 더 많은 기능을 지원합니다)
X 서버와 같은 응용 프로그램은 일반적으로 키보드 드라이버에서 키보드 입력을 얻습니다. Linux에서 범용 입력 추상화 계층을 사용합니다. X 서버는 연결된 응용 프로그램에 키보드 이벤트를 전달하는 이벤트 메커니즘을 제공합니다. 예를 들어, xterm
X11 키보드 이벤트는 수신되어 의사 터미널 장치의 마스터에 문자를 쓰는 것으로 변환되며, 이는 xterm
해당 의사 터미널 슬레이브에서 읽을 때 해당 문자를 읽는 "내부적으로" 실행되는 프로세스로 변환됩니다( /dev/pts/x
). .
이제 그런 일은 없습니다단말 응용. 우리가 말한 것단말 응용위는 터미널에 표시되고 터미널 vi
(예: 대화형 쉘 또는 쉘)에서 입력을 받을 것으로 예상되는 터미널에서 일반적으로 사용되는 응용 프로그램입니다 less
. 그러나 모든 애플리케이션은 터미널에 의해 제어될 수 있으며 파일이나 해당 stdin/stdout/stderr을 읽거나 쓰는 모든 애플리케이션은 터미널 장치에 대한 I/O를 수행할 수 있습니다.
예 를 들어, firefox
실행 중인 쉘에서 사용자 I/O를 위해 X 서버에 연결하는 애플리케이션은xterm
firefox
제어 터미널쉘 부모로부터. ^C
쉘이 포그라운드에서 시작하면 터미널에서 종료됩니다. 또한 파일의 파일 설명자 0, 1, 2(stdin, stdout 및 stderr)를 엽니다 /dev/pts/<x>
(다시 쉘 상위에서 상속됨). 그리고 firefox
fd 2(stderr)에 일종의 오류를 기록하게 될 가능성이 높습니다(백그라운드에 놓고 최종 장치를 구성하면 stty tostop
SIGTTOU를 수신하고 중단됩니다).
반대로, firefox
X 세션 관리자나 Windows 관리자에 의해 실행되면(일부 메뉴에서 일부 Firefox 아이콘을 클릭할 때) 제어 터미널을 얻지 못할 수 있으며 파일 설명자가 터미널에 연결되지 않습니다( ps -fp <firefox-pid>
디스플레이가 표시됩니다). 파일 설명 자나 표시가 없기 ?
때문 tty
입니다 .) 그러나 이를 탐색하면 최종 장치에 대한 일부 I/O를 계속 수행할 수 있습니다. 플래그 없이 파일을 열고 세션 리더이고 아직 세션을 연결하지 않은 경우 장치는 결국 프로세스에 대한 제어 터미널이 됩니다.lsof -p <firefox-pid>
/dev/pts/*
/dev/tty*
file:///dev/pts/<x>
firefox
O_NOCTTY
/dev/pts/<x>
firefox
추가 자료:
편집하다
일부 문제를 명확히 하고 일부 맥락을 추가하기 위해 편집되었습니다.
위의 내용을 통해 프로세스는 원하는 모든 터미널 장치(프로세스가 포그라운드 프로세스 그룹에 속하지 않는 경우 제어 터미널 제외)에서 입력을 읽을 수 있다는 점을 분명히 알 수 있지만 실제로는 관심 있는 것이 아닙니다.
귀하의 질문은 대화형 터미널 응용 프로그램의 경우 stdin이 더 이상 터미널을 가리키지 않을 때 사용자 입력을 얻을 수 있는 위치입니다.
tr
응용 프로그램은 표준 입력에서 입력을 받아 표준 출력에 쓰는 것을 좋아합니다 . stdin/stdout이 다른 쪽 끝에 터미널이 있는 tty 장치인 경우 사용자로부터 데이터를 읽거나 사용자에게 데이터를 쓰기 때문에 대화형이 됩니다.
일부 터미널 텍스트 편집기(예 ed
: ex
일부 구현)는 stdin이 더 이상 터미널이 아닐 때 stdin에서 입력을 계속 읽어서 스크립트를 작성할 수 있습니다.vi
호출기는 사용자의 입력이 터미널이 아니더라도(적어도 출력이 여전히 터미널에 도달하는 경우) 사용자와의 상호 작용이 필요한 일반적인 애플리케이션입니다. 그래서 다른 채널이 필요해요이것터미널 장치는 사용자 입력을 받아들입니다. 문제는 어떤 터미널 장치를 사용해야 하는가입니다.
예, 제어 터미널이어야 합니다. 왜냐하면 그것이 일반적으로 제어 터미널이 의미하는 바이기 때문입니다. Ctrl-C/Z를 누르면 장치는 SIGINT/SIGTSTP를 호출기로 전송하므로 호출기가 동일한 터미널에서 다른 키 입력을 읽는 것이 합리적입니다.
제어 터미널에서 파일 설명자를 얻는 일반적인 방법은 파일을 열고 /dev/tty
그곳으로 리디렉션하는 것입니다. (프로세스가 euid를 변경하여 원래 장치에 대한 읽기 액세스 권한이 없더라도 이 방법은 작동합니다. 이것이 훨씬 좋습니다. 원래 장치(어쨌든 휴대용이 아님)에 대한 경로를 찾는 것보다).
stdin이 tty 장치인 경우에도 일부 호출기는 이를 좋아 less
하거나 most
열 것입니다 /dev/tty
(결국 less < /dev/ttyS0
직렬을 통해 전송되는 내용은 터미널 에뮬레이터 내에서 볼 수 있습니다).
열기에 /dev/tty
실패하는 경우는 일반적으로 터미널을 제어할 수 없기 때문입니다. 누군가는 이것이 당신이 명시적으로 가지고 있기 때문이라고 말할 수도 있습니다.탁월한터미널에서 사용자 상호 작용을 시도해서는 안 되지만 터미널 장치를 제어할 수 없지만 stdin/stdout이 여전히 tty 장치이고 여전히 사용자 상호 작용을 원하는 잠재적인(비정상적인) 상황이 있습니다(예: initrd의 비상 쉘).
따라서 터미널인 경우 표준 입력에서 사용자 상호 작용을 얻는 방법으로 돌아갈 수 있습니다.
stdout이 터미널 장치인지 확인하고 싶다고 말할 수도 있습니다.그리고man -l /dev/stdin < /dev/ttyS0 > /dev/ttyS1
이는 제어 장치와 동일한 최종 장치를 가리키지만(사용자 상호 작용을 위해 호출기를 생성하고 싶지 않은 등 수행 중인 작업을 고려하기 위해 man
), 특히 쉽지 않다는 점을 고려하면 귀찮게 할 가치가 없을 것입니다. 휴대하기 좋게. 이는 또한 표준 출력이 터미널 장치인 한 호출기가 상호 작용할 수 있는 다른 이상한 사용 사례를 깨뜨릴 수도 있습니다.