Tại sao tôi không thể `tail -f / Proc / $ pid / fd / 1`?


10

Tôi đã viết một tập lệnh đơn giản - đó là echoPID của nó:

#/bin/bash

while true; do
    echo $$;
    sleep 0.5;
done

Tôi đang chạy tập lệnh đã nói (nó nói đi nói 3844lại) trong một thiết bị đầu cuối và cố gắng tailmô tả tập tin trong một thiết bị khác:

$ tail -f /proc/3844/fd/1

Nó không in bất cứ thứ gì lên màn hình và treo cho đến khi ^c. Tại sao?

Ngoài ra, tất cả các mô tả tệp STD (IN / OUT / ERR) liên kết đến cùng pts:

$ ls -l /proc/3844/fd/
total 0
lrwx------ 1 mg mg 64 sie 29 13:42 0 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 1 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 2 -> /dev/pts/14
lr-x------ 1 mg mg 64 sie 29 13:42 254 -> /home/user/test.sh
lrwx------ 1 mg mg 64 sie 29 13:42 255 -> /dev/pts/14

Điều này có bình thường không?

Chạy Ubuntu Gnome 14.04.

Nếu bạn nghĩ câu hỏi này thuộc về SO hoặc SU thay vì UL, hãy nói.


Câu trả lời:


13

Thực hiện một stracesố tail -f, nó giải thích tất cả mọi thứ. Phần thú vị:

13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 fstatfs(3, {...}) = 0
13791 inotify_init()                    = 4
13791 inotify_add_watch(4, "/path/to/file", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 read(4, 0xd981c0, 26)             = -1 EINTR (Interrupted system call)

Những gì nó làm? Nó thiết lập một inotifytrình xử lý cho tệp, và sau đó đợi cho đến khi có điều gì đó xảy ra với tệp này. Nếu kernel nói tailthông qua trình xử lý inotify này, rằng tệp đã thay đổi (thông thường, đã được nối thêm), thì tail1) tìm 2) đọc các thay đổi 3) ghi chúng ra màn hình.

/proc/3844/fd/1trên hệ thống của bạn là một liên kết tượng trưng đến /dev/pts/14, đó là một thiết bị nhân vật. Không có thứ gì giống như "bản đồ bộ nhớ", có thể được truy cập bằng thứ đó. Do đó, không có gì mà những thay đổi của chúng có thể được ký vào inotify, bởi vì không có vùng đĩa hoặc vùng nhớ nào có thể được truy cập bởi điều đó.

Thiết bị nhân vật này là một thiết bị đầu cuối ảo, thực tế hoạt động như thể nó là một ổ cắm mạng. Các chương trình chạy trên thiết bị đầu cuối ảo này đang kết nối với thiết bị này (giống như khi bạn telnet-ted vào cổng tcp) và viết những gì chúng muốn viết vào. Cũng có những thứ phức tạp hơn, ví dụ như khóa màn hình, các chuỗi điều khiển đầu cuối và như vậy, những thứ này thường được xử lý bằng ioctl()các cuộc gọi.

Tôi nghĩ rằng, bạn muốn bằng cách nào đó xem một thiết bị đầu cuối ảo. Nó có thể được thực hiện trên linux, nhưng nó không đơn giản như vậy, nó cần một số chức năng giống như proxy mạng và một chút sử dụng khéo léo của các ioctl()cuộc gọi này . Nhưng có những công cụ có thể làm điều đó.

Hiện tại tôi không thể nhớ, gói debian nào có công cụ cho mục tiêu này, nhưng với một chút googling bạn có thể tìm thấy nó có thể dễ dàng.

Tiện ích mở rộng: như @Jajesh đã đề cập ở đây (cho anh ta +1 nếu bạn cho tôi), công cụ được đặt tên watch.

Phần mở rộng số 2: @kelnos đã đề cập, một đơn giản cat /dev/pts/14cũng là đủ. Tôi đã thử điều đó, và vâng, nó hoạt động, nhưng không chính xác. Tôi không thử nghiệm rất nhiều với điều đó, nhưng có vẻ như với tôi như thể một đầu ra đi vào thiết bị đầu cuối ảo đi hoặc đến catlệnh, hoặc đến vị trí ban đầu của nó, và không bao giờ để cả hai. Nhưng nó không chắc chắn.


Câu trả lời của peterh taillà chính xác (bit đồng hồ inotify), nhưng anh ta không chính xác ở chỗ thực sự rất đơn giản để làm những gì bạn muốn: chỉ cần sử dụng catthay vì tail.
kelnos

@kelnos Cảm ơn, tôi sẽ thử điều đó và mở rộng câu trả lời của tôi với kết quả.
peterh - Phục hồi Monica

@kelnos catcũng không hoạt động với tôi, nó cũng treo theo cách tương tự và tất cả những gì tôi có thể làm là làm ctrl+c.
cprn

1
Tôi vẫn không hiểu. Tôi đã thay đổi echo $$để echo $$ >> foobây giờ có một tệp và quá trình mở nó và thêm vào đó cứ sau 0,5 giây. Tôi vẫn không thể truy cập nó thông qua bộ mô tả tệp và tất cả các bộ mô tả tệp trong /proc/$pid/fd/(nhưng 254 liên kết đến test.shchính tập lệnh) liên kết đến /dev/pts/14. Làm thế nào để bash truy cập foonó viết?
cprn

1
kỳ lạ, nó dường như chỉ hoạt động trong một số tình huống. sử dụng tập lệnh trong câu hỏi, nó không hoạt động. nhưng nếu tôi thực hiện "echo $$" trong một cái vỏ, và sau đó con mèo FD 1 trên cái vỏ đó trong một cái vỏ khác, mọi thứ tôi gõ trong cái vỏ thứ nhất sẽ được lặp lại trong cái thứ hai.
kelnos

4

Các tệp trong /dev/ptskhông phải là các tệp thông thường, chúng là các thẻ điều khiển cho các thiết bị đầu cuối ảo. Một ptshành vi để đọc và viết không đối xứng (nghĩa là những gì được viết trong đó sau này có thể được đọc từ nó, như một tệp thông thường hoặc fifo / pipe), nhưng được trung gian bởi quá trình tạo ra thiết bị đầu cuối ảo: một số phổ biến là xterm hoặc ssh hoặc agetty hoặc màn hình. Quá trình kiểm soát thường sẽ gửi các lần nhấn phím đến các quy trình đọc ptstệp và hiển thị trên màn hình những gì họ viết trên pts.

Do đó, tail -f /dev/pts/14sẽ in các phím bạn chạm vào thiết bị đầu cuối mà bạn đã khởi động tập lệnh của mình và nếu bạn thực hiện echo meh > /dev/pts/14thì mehthông báo sẽ xuất hiện trong thiết bị đầu cuối.


Bạn có quyền nói rằng tôi có thể viết thư cho thiết bị pts nhưng dường như tôi không thể đọc được từ thiết bị. Như trong: tail -f /dev/pts/14không in các phím tôi chạm vào thiết bị đầu cuối đó. Đó là một câu trả lời thú vị, mặc dù. Cảm ơn.
cprn

0

Một thời gian trước, tôi tìm thấy một kinda workaround rằng đôi khi câu trả lời về sự cần thiết để kiểm tra những gì đang được xuất ra STDOUT, giả sử bạn có một pidcủa quá trình này và bạn có thể trần mắt không thân thiện kết quả:

sudo strace -p $pid 2>&1 | grep write\(

-1

Tôi đoán, đối với điều này thay vì theo đuôi, những gì bạn cần làm sẽ là xem đầu ra.

$ watch -n2 ls -l /proc/3844/fd/

Hy vọng đây là những gì bạn cần.


2
Lệnh này sẽ hiển thị danh sách các fds mở cứ sau 2 giây, chứ không phải đầu ra nội dung trên thiết bị xuất chuẩn.
Ángel

Ángel, đúng. Anh ta có thể sử dụng đồng hồ với một con mèo để xem kết quả mà anh ta muốn theo dõi. Tôi đoán @ peter-horvath, đã đưa ra lời giải thích hoàn hảo cho câu hỏi.
Jayesh

Tôi biết watch. Những gì tôi đang cố gắng làm là nhìn trộm đầu ra của quy trình đã chạy, vì vậy watchkhông có ích.
cprn
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.