알겠어요파일 설명자(또는 파일 핸들러) 예파일 IO 기술리눅스 시스템에서.
또한 모든 프로세스에는 0부터 3까지의 설명자가 있는 파일로 표시되는 3개의 표준 스트림(즉, stdin, stdout 및 stderr)이 있다는 것도 알고 있습니다.
그러나 내가 확인한 모든 프로세스에는 lsof -p <pid>
읽기 권한이 있는 추가 파일 설명자가 있는 것으로 나타났습니다.255
~에서이 답변, 나는 이 기능이 다음에 특정하다는 것을 배웠습니다.배쉬 쉘, 그러나 답변이나 인용된 소스 중 어느 것도 실제로 이 파일 설명자가 사용되는 용도를 설명하지 않습니다.
내 질문:
- 255 파일 설명자의 용도는 무엇입니까?
- 내 Bash 스크립트에서 이것을 사용할 수 있나요? 아니면 수동으로 사용/조작해서는 안되는 내부 작업 메커니즘입니까?
답변1
질문의 마지막 부분은 다음과 같습니다.
사용할 수 있나요?
에서 man bash
:
9보다 큰 파일 설명자를 사용하는 리디렉션은 쉘에서 내부적으로 사용되는 파일 설명자와 충돌할 수 있으므로 주의해서 사용해야 합니다.
따라서 해당 번호로 새 파일 설명자를 생성한다는 의미라면 대답은 '아니요'입니다.
as를 사용하여 "해당 fd에 쓰기"를 의미하는 경우:
$ echo hello >/dev/fd/255"
또는 다음에서 읽어보세요:
$ read a </dev/fd/255
abc
$ echo "$a"
abc
대답은 '예'입니다.
그러나 아마도 /dev/tty
그것을 사용하여 tty
.
파일 설명자 255는 무엇에 사용됩니까?
/dev/stdout
fd 1( ) 및 fd 0( /dev/stdin
)이 차단된 경우 tty에 대한 대체 연결 역할을 합니다 .
다른 쉘에서는 다른 숫자를 사용할 수 있습니다(예: zsh에서는 10).
$ zsh
mail% ls -l /proc/self/fd /proc/$$/fd/* &
[1] 3345
mail% lrwx------ 1 isaac isaac 64 Oct 14 09:46 /proc/3250/fd/0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/10 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/2 -> /dev/pts/2
/proc/self/fd:
total 0
lrwx------ 1 isaac isaac 64 Oct 14 09:50 0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 2 -> /dev/pts/2
lr-x------ 1 isaac isaac 64 Oct 14 09:50 3 -> /proc/3345/fd
[1] + done ls -l /proc/self/fd /proc/$$/fd/*
mail%
~에서메일링 리스트:
Fd 255는 내부적으로 tty에 대한 연결로 사용되므로 exec를 사용하여 fd를 재배치하는 데 방해가 되지 않습니다. 같은 이유로 Bash는 프로세스 대체 "<(foo)"를 처리할 때 높은 fd를 할당합니다.
안드레아스 슈왑
답변2
이 파일 설명자는 제어 tty에 대한 열린 핸들이며 255
대화형 모드에서 실행될 때만 사용됩니다.bash
이를 통해 작업 제어 실행을 허용하면서 메인 셸에서 리디렉션할 수 있습니다 stderr
(즉, ^C로 프로세스를 종료하고 ^Z로 프로세스를 중단하는 기능 등).
예:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
ksh93
단순히 파일 설명자 2를 제어 터미널에 대한 참조로 사용하는 이와 같은 셸에서 이 작업을 시도하면 sleep
프로세스는 ^C 및 ^Z의 영향을 받지 않으며 다른 창/세션에서 종료되어야 합니다. 이는 파일 설명자 2가 더 이상 터미널을 가리키지 않기 때문에 쉘이 이를 사용하여 프로세스 그룹을 sleep
터미널의 전경 프로세스 그룹 으로 설정할 수 없기 때문입니다 .tcsetgrp()
이것은 구체적이지 않고 합계 bash
에도 적용됩니다 . 단지 설명자가 그렇게 높게 이동되지 않은 것뿐입니다(보통 10).dash
zsh
zsh
이 fd는 프롬프트와 사용자 입력을 에코하는 데에도 사용되므로 다음을 수행하십시오.
$ exec 2>/tmp/err
$
다른 답변 및 의견에서 제안한 것처럼 스크립트를 읽고 파이프를 설정할 때 사용되는 파일 핸들과는 아무런 관련이 없습니다 bash
(이 파이프는 동일한 기능을 사용하여 복사됩니다 - ).move_to_high_fd()
bash
이렇게 큰 숫자를 사용하는 것은 fd가 (예를 들어 ) 쉘 내 리디렉션 9
에 사용되는 값 보다 더 커지도록 허용하는 것입니다 . 다른 쉘은 이를 지원하지 않습니다.exec 87<filename
파일 핸들을 직접 사용할 수도 있지만 파일 핸들을 얻을 수 있으므로 그렇게 하는 것은 별 의미가 없습니다.동일한... < /dev/tty
다음을 사용하여 모든 명령에서 터미널을 제어하십시오 .
bash 소스 코드 분석:
에서는 bash
제어 터미널의 파일 설명자가 shell_tty
변수에 저장됩니다. 셸이 대화형인 경우 변수는 터미널에 jobs.c:initialize_job_control()
연결된 stderr
경우 stderr
복사하거나 직접 열어서(시작 시 또는 실행 실패 후) 초기화됩니다 /dev/tty
. 그런 다음 상위 fd에 다시 복사합니다 general.c:move_to_high_fd()
.
int
initialize_job_control (force)
int force;
{
...
if (interactive == 0 && force == 0)
{
...
}
else
{
shell_tty = -1;
/* If forced_interactive is set, we skip the normal check that stderr
is attached to a tty, so we need to check here. If it's not, we
need to see whether we have a controlling tty by opening /dev/tty,
since trying to use job control tty pgrp manipulations on a non-tty
is going to fail. */
if (forced_interactive && isatty (fileno (stderr)) == 0)
shell_tty = open ("/dev/tty", O_RDWR|O_NONBLOCK);
/* Get our controlling terminal. If job_control is set, or
interactive is set, then this is an interactive shell no
matter where fd 2 is directed. */
if (shell_tty == -1)
shell_tty = dup (fileno (stderr)); /* fd 2 */
if (shell_tty != -1)
shell_tty = move_to_high_fd (shell_tty, 1, -1);
...
}
shell_tty
아직 제어 tty가 아닌 경우 다음과 같이 설정하십시오.
/* If (and only if) we just set our process group to our pid,
thereby becoming a process group leader, and the terminal
is not in the same process group as our (new) process group,
then set the terminal's process group to our (new) process
group. If that fails, set our process group back to what it
was originally (so we can still read from the terminal) and
turn off job control. */
if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp)
{
if (give_terminal_to (shell_pgrp, 0) < 0)
shell_tty
그런 다음 사용
tc[sg]etpgrp
injobs.c:maybe_give_terminal_to()
및를 사용하여jobs.c:set_job_control()
포그라운드 프로세스 그룹을 가져오고 설정합니다.jobs.c:give_terminal_to()
termios(3)
및 에서 매개변수 가져오기 및 설정jobs.c:get_tty_state()
jobs.c:set_tty_state()
ioctl(TIOCGWINSZ)
터미널 창 크기를 얻으려면 in을 사용하십시오lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
일반적으로 사용되는 모든 임시 파일 설명자(스크립트 파일, 파이프 등)와 함께 사용되므로 bash
Google 검색에서 강조된 대부분의 주석에서 혼란이 발생합니다.
내부적으로 사용되는 파일 설명자는 bash
실행 shell_tty
시 닫기로 설정되어 명령에 누출되지 않습니다.