Tại sao quá trình thay thế dẫn đến một tệp có tên / dev / fd / 63 là một đường ống?


40

Tôi đang cố gắng để hiểu các đường ống được đặt tên trong bối cảnh của ví dụ cụ thể này.

Tôi gõ <(ls -l)vào terminal của tôi và nhận đầu ra là bash: /dev/fd/63: Permission denied.

Nếu tôi gõ cat <(ls -l), tôi có thể thấy nội dung thư mục. Nếu tôi thay thế catbằng echo, tôi nghĩ rằng tôi nhận được tên thiết bị đầu cuối (hoặc là nó?).

echo <(ls -l)cho đầu ra như /dev/fd/63.

Ngoài ra, ví dụ đầu ra này không rõ ràng với tôi.

ls -l <(echo "Whatever")
lr-x------ 1 root root 64 Sep 17 13:18 /dev/fd/63 -> pipe:[48078752]

Tuy nhiên, nếu tôi đưa ra, ls -l <()nó liệt kê cho tôi nội dung thư mục.

Điều gì đang xảy ra trong trường hợp của đường ống được đặt tên?

Câu trả lời:


37

Khi bạn thực hiện <(some_command), trình bao của bạn thực thi lệnh bên trong dấu ngoặc đơn và thay thế toàn bộ bằng một bộ mô tả tệp, được kết nối với thiết bị xuất chuẩn của lệnh. Vì vậy, /dev/fd/63một đường ống có chứa đầu ra của cuộc gọi ls của bạn.

Khi bạn làm điều <(ls -l)bạn nhận được một Permission deniedlỗi, bởi vì toàn bộ đường được thay thế bằng đường ống, có hiệu quả cố gắng để gọi /dev/fd/63như một lệnh, mà không phải là thực thi.

Trong ví dụ thứ hai của bạn, cat <(ls -l)trở thành cat /dev/fd/63. Khi mèo đọc từ các tệp được cung cấp dưới dạng tham số, bạn sẽ có được nội dung. echomặt khác chỉ xuất ra các tham số "nguyên trạng".

Trường hợp cuối cùng bạn có, <()chỉ đơn giản là được thay thế bởi không có gì, vì không có lệnh. Nhưng điều này không nhất quán giữa các shell, trong zsh bạn vẫn nhận được một đường ống (mặc dù trống).

Tóm tắt : <(command)cho phép bạn sử dụng thông số của lệnh, trong đó bạn thường sẽ cần một tệp.

Chỉnh sửa: như Gilles chỉ ra, đây không phải là một ống có tên, mà là một ống ẩn danh. Sự khác biệt chính là, nó chỉ tồn tại, miễn là quá trình đang chạy, trong khi một đường ống có tên (được tạo ra với mkfifo) sẽ ở lại mà không có các quy trình gắn liền với nó.


5
mkfifochỉ tạo ra các ống được đặt tên, không có bất kỳ nội dung. Vì vậy, bạn cần phải viết cho chính mình (ví dụ mkfifo mypipe; ls > mypipe). Và có, ghi vào đường ống sẽ chặn cho đến khi một số quá trình đọc từ đường ống.
crater2150

6
Không có tên ống ở đây. /dev/fd/63là một đường ống ẩn danh.
Gilles 'SO- ngừng trở nên xấu xa'

1
@ crater2150, @Gilles / dev / fd / 63 thực sự là một ống có tên. Kiểm tra điều này với một cái gì đó như file <(ls). Shell này tạo ra một ống ẩn danh, nhưng bộ mô tả tệp phản ánh như một ống có tên trong /dev/fd. Nếu đó là một đường ống ẩn danh, nó sẽ không có tên và không thể được mở bằng lệnh /dev/fd/63được thông qua.
rv

2
@rv Nó vẫn là một đường ống nặc danh. Thực tế là có một tên tập tin đó đề cập đến ống ẩn danh này không làm cho nó một ống tên: một ống tên là khác nhau, nó tồn tại ở đâu đó trên một hệ thống tập tin, có quyền và quyền sở hữu vv Entries của /dev/fdcó thể tham khảo bất kỳ tập tin mô tả, thậm chí các đường ống và ổ cắm ẩn danh, ổ cắm mạng, phân đoạn bộ nhớ được chia sẻ, v.v.
Gilles 'SO- ngừng trở nên xấu xa'

1
Tại sao nó là 63 , mặc dù?
K3 --- rnc

-4

Bạn hiểu sai cả lslệnh và chuyển hướng. lsliệt kê các tệp và thư mục được cung cấp trên dòng lệnh, tôi không tin rằng nó chấp nhận bất kỳ đầu vào nào từ stdin. Chuyển hướng > >><là cách sử dụng tệp để cung cấp đầu vào và thu thập đầu ra.


1
Không có chuyển hướng từ một tập tin ở đây. <(…)là một quá trình thay thế.
Gilles 'SO- ngừng trở nên xấu xa'

1
@IMSoP - như Gilles đã nói - nó không phải là một đường ống có tên - đó là một đường ống ẩn danh. Nó rất giống với x|yvà gần giống với [num]<<REDIRECTtrong một số vỏ. Trường hợp khác nhau là sự thay thế theo nghĩa đen của shell của liên kết fd - /dev/fd/63và vv và những gì nó làm - hoặc không làm - với stdin. Làm echo | readlink /dev/fd/0và xem cho chính mình.
mikeerv

1
@IMSoP - đó là một devliên kết - một tệp đặc biệt. bạn có thể thực hiện cùng một mô tả tập tin trên hầu hết các hệ thống linux - thậm chí là điển hình |pipes, mặc dù tôi sẽ không chứng minh cho hành vi ở nơi khác. Tôi đến từ nơi bạn đến, nhưng một ống có tên là một thứ riêng biệt - đó là một tham chiếu hệ thống tệp đến một ống trong nhân - một tham chiếu hệ thống tệp thông thường , không phải là tệp thiết bị.
mikeerv

1
@mikeerv Thật thú vị, hướng dẫn Bash đề cập rằng nó sẽ hoạt động trên các hệ thống mà không cần /dev/fd/*tạo một đường ống có tên ở một nơi khác. Nhưng tôi cho rằng /dev/fd/*chính nó là một cơ chế khác với một đường ống có tên thích hợp. Ngẫu nhiên, mô tả của Wikipedia có thể làm với một lời giải thích về sự khác biệt này.
IMSoP

1
@mikeerv Theo các tài liệu tham khảo khác mà tôi tìm thấy, nó đơn giản hơn thế: nếu /dev/fd/*không có sẵn, bash sẽ tạo một ống có tên /tmpvà thay vào đó sử dụng nó để thay thế quy trình. Có vẻ không lạ lắm đối với tôi, chỉ làm cho chức năng có sẵn trong càng nhiều môi trường càng tốt.
IMSoP
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.