Bộ 255
mô tả tệp đó là một điều khiển mở cho tty kiểm soát và chỉ được sử dụng khi bash
được chạy trong chế độ tương tác.
Nó cho phép bạn chuyển hướng stderr
trong vỏ chính, trong khi vẫn cho phép điều khiển công việc hoạt động (nghĩa là có thể tiêu diệt các tiến trình với ^ C, làm gián đoạn chúng bằng ^ Z, v.v.).
Thí dụ:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
Nếu bạn thử trong shell như ksh93
, chỉ đơn giản là sử dụng mô tả tệp 2 làm tham chiếu đến thiết bị đầu cuối kiểm soát, sleep
quá trình sẽ trở nên miễn nhiễm với ^ C và ^ Z, và sẽ phải bị giết từ một cửa sổ / phiên khác. Đó là bởi vì shell sẽ không thể đặt nhóm quy trình sleep
làm tiền cảnh trong thiết bị đầu cuối tcsetgrp()
, vì mô tả tệp 2 không còn trỏ đến thiết bị đầu cuối.
Điều này không bash
cụ thể, nó cũng được sử dụng trong dash
và zsh
, chỉ có điều là bộ mô tả không được di chuyển quá cao (thường là 10).
zsh
cũng sẽ sử dụng fd đó để lặp lại lời nhắc và nhập liệu của người dùng, vì vậy, đơn giản như sau sẽ hoạt động:
$ exec 2>/tmp/err
$
Nó không liên quan gì đến việc xử lý tệp bash
đang sử dụng khi đọc tập lệnh và thiết lập các đường ống (cũng bị chặn ngoài cùng một chức năng - move_to_high_fd()
), như đã được đề xuất trong các câu trả lời và nhận xét khác.
bash
đang sử dụng một số lượng lớn như vậy để cho phép fds lớn hơn 9
được sử dụng với các chuyển hướng trong vỏ (ví dụ. exec 87<filename
); Điều đó không được hỗ trợ trong các shell khác.
Bạn có thể sử dụng tệp đó tự xử lý, nhưng có rất ít điểm khi làm như vậy, bởi vì bạn có thể có một điều khiển đến cùng một thiết bị đầu cuối kiểm soát trong bất kỳ lệnh nào với ... < /dev/tty
.
Phân tích mã nguồn của bash :
Trong bash
, mô tả tập tin của thiết bị đầu cuối kiểm soát được lưu trữ trong shell_tty
biến. Nếu shell tương tác, biến đó được khởi tạo (khi khởi động hoặc sau khi thực thi không thành công) jobs.c:initialize_job_control()
bằng cách nhân đôi nó từ stderr
(nếu stderr
được gắn vào thiết bị đầu cuối) hoặc bằng cách mở trực tiếp /dev/tty
, và sau đó được nhân đôi lại với fd cao hơn với 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);
...
}
Nếu shell_tty
chưa phải là tty kiểm soát, thì nó được thực hiện như vậy:
/* 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
sau đó được sử dụng để
nhận được và thiết lập các nhóm quá trình foreground với tc[sg]etpgrp
trong jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
vàjobs.c:give_terminal_to()
nhận và thiết lập các thông số termios(3)
trong jobs.c:get_tty_state()
vàjobs.c:set_tty_state()
có được kích thước cửa sổ terminal với ioctl(TIOCGWINSZ)
trong lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
thường được sử dụng với tất cả các mô tả tệp tạm thời được sử dụng bởi bash
(tệp script, ống dẫn, v.v.), từ đó gây nhầm lẫn trong hầu hết các bình luận xuất hiện nổi bật trong các tìm kiếm của google.
Các bộ mô tả tệp được sử dụng bên trong bash
, bao gồm shell_tty
tất cả được đặt thành close-on-exec, vì vậy chúng sẽ không bị rò rỉ cho các lệnh.