Làm thế nào để `less` lấy dữ liệu từ stdin trong khi vẫn có thể đọc lệnh từ người dùng?


47

Vì hầu hết các bạn đã thực hiện nhiều lần, thật tiện lợi khi xem văn bản dài bằng cách sử dụng less:

some_command | less

Bây giờ stdin của nó được kết nối với một đường ống (FIFO). Làm thế nào nó vẫn có thể đọc các lệnh như lên / xuống / thoát?


15
lessđọc dữ liệu để hiển thị từ stdin và nó đọc các lệnh từ tty. Chúng là những thứ khác nhau.
William Pursell

2
@WilliamPursell Vâng tôi biết. Nhưng chỉ có một luồng đầu vào tiêu chuẩn, phải không?
iBug

4
Có, có một luồng đầu vào và một tty. lessđọc dữ liệu từ stdin và các lệnh từ tty.
William Pursell

Câu trả lời:


52

Như William Pursell đã đề cập , lessđọc tổ hợp phím của người dùng từ thiết bị đầu cuối. Nó rõ ràng mở ra /dev/tty, các thiết bị đầu cuối kiểm soát; cung cấp cho nó một bộ mô tả tệp, tách biệt với đầu vào tiêu chuẩn, từ đó nó có thể đọc đầu vào tương tác của người dùng. Nó có thể đồng thời đọc dữ liệu để hiển thị từ đầu vào tiêu chuẩn của nó nếu cần thiết. (Nó cũng có thể ghi trực tiếp vào thiết bị đầu cuối nếu cần thiết.)

Bạn có thể thấy điều này xảy ra bằng cách chạy

some_command | strace -o less.trace -e open,read,write less

Di chuyển xung quanh đầu vào, thoát lessvà xem nội dung của less.trace: bạn sẽ thấy nó mở /dev/ttyvà đọc từ cả hai mô tả tệp 0 và bất kỳ cái nào được trả về khi mở ra /dev/tty(có thể là 3).

Đây là thực tế phổ biến cho các chương trình muốn đảm bảo họ đọc và ghi vào thiết bị đầu cuối. Một ví dụ là SSH, ví dụ khi nó yêu cầu mật khẩu hoặc cụm mật khẩu.

Như được giải thích bởi schily , nếu /dev/ttykhông thể mở được, lesssẽ đọc từ lỗi tiêu chuẩn của nó (mô tả tệp 2). lessViệc sử dụng /dev/ttyđã được giới thiệu trong phiên bản 177, phát hành vào ngày 2 tháng 4 năm 1991.

Nếu bạn thử chạy cat /dev/tty | less, như được đề xuất bởi Hagen von Eitzen , lesssẽ thành công trong việc mở /dev/ttynhưng sẽ không nhận được bất kỳ đầu vào nào từ nó cho đến khi catđóng nó. Vì vậy, bạn sẽ thấy màn hình trống, và không có gì khác cho đến khi bạn nhấn CtrlCđể giết cat(hoặc giết nó theo một cách khác); sau đó lesssẽ hiển thị bất cứ thứ gì bạn gõ khi catđang chạy và cho phép bạn kiểm soát nó.


4
@HagenvonEitzen Máy tính của bạn sẽ phát nổ! Nó giống như cách Kirk và Spock khiến android của Mudd sụp đổ.
Barmar

7
@HagenvonEitzen Wow. Một cách sử dụng gấp đôi vô dụng của con mèo . Tôi rất ấn tượng.
Andrew Henle

8
@grawity Tôi nghĩ rằng quan điểm của Andrew là cat blah |có thể được thay thế < blahvà thậm chí điều đó không cần thiết trong trường hợp này vì less blahnó cũng hoạt động (tốt, less -f /dev/tty). Nhưng đọc từ /dev/ttylà một chút của một trường hợp đặc biệt, và cả ba biến thể ( cat /dev/tty | less, less < /dev/ttyless -f /dev/tty) tạo ra kết quả khác nhau.
Stephen Kitt

1
Có / dev / tty luôn luôn chỉ đúng chỗ không? Tôi nghĩ bạn thường cần sử dụng / dev / ptsX?
StarWeaver

2
@StarWeaver thấy câu hỏi này về sự khác biệt giữa /dev/tty/dev/pts/....
Stephen Kitt

26

UNIX cung cấp hai phương thức để đọc đầu vào của người dùng trong khi stdin đã được chuyển hướng:

  • Phương pháp ban đầu là đọc từ stderr . Stderr được mở để viết đọc và điều này vẫn được đề cập trong POSIX.

  • Các phiên bản UNIX sau này đã làm (khoảng năm 1979) thêm /dev/ttygiao diện trình điều khiển cho phép mở tty kiểm soát của một quy trình. Vì có các quy trình mà không có tty kiểm soát, có thể một nỗ lực để mở /dev/ttythất bại. Do đó, phần mềm bằng văn bản thân thiện có dự phòng cho phương thức ban đầu và sau đó cố gắng đọc từ thiết bị lỗi chuẩn.


11
Đọc từ stderr? Đã học được điều gì đó mới.
iBug

1
Tôi rất vui vì ai đó nhớ những cách cũ.
Joshua

3
Là lý do mà stderr được sử dụng để đọc, bởi vì nó ít có khả năng được chuyển hướng nhất? Tôi không thấy bất kỳ sự khác biệt nào khác giữa nó và thiết bị xuất chuẩn (hoặc cho mater stdin đó, trước khi chuyển hướng).
ctrl-alt-delor

4
Vâng, đó là bởi vì đây là mô tả tập tin có ít cơ hội nhất để được chuyển hướng.
schily

@ ctrl-alt-delor: Đó là / điển hình cho các shell đang chạy với stdin, stdout và stderr, tất cả đều là các dup()cam kết của cùng một mô tả tệp, mặc dù, tất cả đều được mở trên tty. (Rõ ràng POSIX vẫn đòi hỏi hoặc gợi ý (câu trả lời này không nói) mà stderr là một đọc / ghi FD, không mở ra với một cái gì đó giống như open("/dev/ttyS0", O_WRONLY)Reading stderr sẽ thất bại trong trường hợp đó..)
Peter Cordes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.