Sự khác biệt giữa STDIN và các đối số được truyền cho lệnh là gì?


16

Tôi có thể sử dụng một trong hai hình thức để thực hiện catphương thức:

cat file_name
cat < file_name

Kết quả là như nhau

Sau đó, tôi muốn thực hiện mantheo định dạngstdin

man < file_name

Trong khi file_namecó chứa:

# file_name
cat

Nhưng nó bật lên What manual page do you want?thay vì thực thi man cat.

Tôi muốn biết tại sao catcó thể chấp nhận stdinnhư là đối số nhưng mankhông thể. Và sự khác biệt giữa các đối số dòng lệnh và stdin?

Câu trả lời:


21

Câu hỏi của bạn liên quan chặt chẽ đến cách trình bao bạn đang sử dụng phân tích cú pháp đầu vào của người dùng trên dòng lệnh.

Nếu từ đầu tiên trên dòng lệnh là một chương trình, nằm trong một thư mục đặc biệt (chủ yếu được xác định bởi PATH) và không có ký tự đặc biệt nào được đưa ra (tùy thuộc vào trình bao bạn đang sử dụng), tất cả các từ tiếp theo được phân tách bằng dấu cách hoặc tab được chuyển đến chương trình ở dạng đặc biệt tức là một mảng. Với mỗi từ là một yếu tố trong mảng.

Làm thế nào chương trình, bạn sẽ gọi phiên dịch các đối số (nằm trong mảng) phụ thuộc vào cách nó được lập trình. Có một số tiêu chuẩn gần đúng về cách cú pháp của các đối số sẽ trông như thế nào nhưng nói chung, lập trình viên hoàn toàn miễn phí. Vì vậy, đối số đầu tiên có thể được hiểu là tên của một tệp hoặc bất cứ điều gì lập trình viên nghĩ đến tại thời điểm ông viết chương trình.

Trong trường hợp bạn thêm ký tự đặc biệt <hoặc >vào dòng lệnh của mình, shell sẽ không nối <>các từ tiếp theo vào mảng sẽ được chuyển đến chương trình. Với <hoặc >được cung cấp, shell bắt đầu tạo ra những thứ ưa thích, được hỗ trợ bởi kernel bên dưới ( đường ống từ khóa ). Để nắm bắt những gì đang diễn ra, bạn phải hiểu những gì STDINSTDOUT(vì nó không liên quan ngay lập tức tôi bỏ qua STDERR).

Mọi thứ bạn có thể nhìn thấy trên thiết bị đầu cuối của bạn (trong hầu hết các trường hợp, một phần của màn hình của bạn) được ghi bởi trình bao hoặc bất kỳ chương trình nào khác mà bạn đã gọi trước đó vào một tệp đặc biệt (trong unix mọi thứ đều là một tệp ). Tập tin này có một id đặc biệt và được gọi STDOUT. Nếu một chương trình muốn đọc dữ liệu từ bàn phím, nó sẽ không thăm dò trực tiếp bàn phím (ít nhất là trong hầu hết các trường hợp) nhưng đọc từ một tệp đặc biệt được gọi STDIN. Trong nội bộ tập tin này được kết nối với thiết bị đầu vào tiêu chuẩn của bạn, bàn phím của bạn trong hầu hết các trường hợp.

Nếu shell đọc <hoặc >trong một dòng lệnh được phân tích cú pháp, nó sẽ thao tác STDINhoặc STDOUTtrong một loại cụ thể trong thời gian chương trình tương ứng đang chạy. STDINvà không STDOUTchỉ đến thiết bị đầu cuối hoặc thiết bị đầu vào tiêu chuẩn nữa mà thay vào đó là tên tệp tiếp theo trên dòng lệnh.

Trong trường hợp của hai dòng

cat file_name
cat < file_name

hành vi được quan sát là giống hệt nhau vì nhà phát triển tương ứng thực hiện catđể đọc dữ liệu từSTDIN hoặc đọc dữ liệu từ tệp, tên được đặt làm đối số dòng lệnh đầu tiên (là thành phần đầu tiên trong mảng mà shell truyền đến cat). Sau đó, catviết toàn bộ nội dung của file_namehoặc STDINcho thiết bị đầu cuối vì chúng tôi không hướng dẫn trình vỏ thao tác STDOUT. Hãy nhớ rằng trong dòng thứ hai, shell của bạn thao tác STDINtheo cách này, nó không trỏ đến thiết bị đầu vào tiêu chuẩn của bạn nữa mà chỉ vào một tệp được gọi file_nametrong thư mục làm việc hiện tại của bạn.

Trong trường hợp khác của dòng

man < file_name

mankhông có nghĩa là đọc bất cứ thứ gì STDINnếu nó được gọi mà không có đối số tức là một mảng trống. Vì vậy, dòng

man < file_name

bằng

man

Ví dụ mansẽ đọc một cái gì đó từ STDIN, quá nếu bạn vượt qua -l -để man. Với tùy chọn này được cung cấp trên dòng lệnh, bạn có thể hiển thị nội dung của mọi thứman đọc từ STDINtrên thiết bị đầu cuối của bạn. Vì thế

man -l - < file_name

cũng sẽ hoạt động (nhưng hãy cẩn thận mankhông chỉ là máy nhắn tin mà còn phân tích cú pháp đầu vào của tệp và do đó nội dung tệp và nội dung được hiển thị có thể khác nhau).

Vậy làm thế nào STDIN , STDOUTvà các đối số dòng lệnh được hiểu là tất cả các thiết lập của nhà phát triển tương ứng.

Tôi hy vọng câu trả lời của tôi có thể làm sáng tỏ mọi thứ.


Cảm ơn lời giải thích chi tiết này. Đối với một vài đoạn cuối của bạn, bạn đã đề cập đến việc sử dụng man -l - < file_nameđể mandiễn giải STDINthành đối số, nhưng nó thất bại trong hệ thống của tôi với STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang

Không có gì. Nhưng tôi đã không đề cập rằng ít nhất phiên bản man( man-db ) của tôi đọc các đối số STDINvới các đối số đã cho -ltheo sau -. Nó chỉ diễn giải dữ liệu từ STDINmột trang nam. Để giải thích chi tiết hơn về các đối số hợp lệ và cách chúng được giải thích, bạn phải tham khảo trang hướng dẫn của chương trình liên quan. Trong trường hợp của bạn tham khảo ý kiến man man. Có lẽ có một lựa chọn tương tự cho bạn man. Nếu bạn muốn đọc các đối số dòng lệnh cho một chương trình cụ thể từ STDIN xargs(như đã đề cập ở trên) là cách để đi.
dùng114632

Tôi man manvà tìm thấy một trong hệ điều hành của tôi không hỗ trợ nó. Dù sao, cảm ơn cho tuyên bố này của hai khái niệm cho tôi.
steveyang

Tôi đã chỉnh sửa câu trả lời của bạn để nó chứa các liên kết thực sự hữu ích thay vì lmgtfy. Đăng liên kết lmgtfy là 1) thô lỗ, 2) không có ích và 3) thực sự cau mày trên các trang web SE. Hoặc cung cấp một liên kết hoặc không nhưng nếu bạn chọn làm như vậy, hãy cung cấp một liên kết đến thông tin thực tế và không phải là một cách mỉa mai chỉ cho ai đó cách tìm thấy nó.
terdon

12

Chúng hoàn toàn khác nhau. Các đối số dòng lệnh được truyền cho chương trình trong một mảng và nó có thể thực hiện những gì nó muốn với chúng; stdin là một luồng đầu vào mà chương trình phải yêu cầu dữ liệu từ. Các chương trình xử lý tệp thường chọn hỗ trợ cả hai, nhưng chúng phải thực hiện thủ công - chúng kiểm tra xem tên tệp có được truyền dưới dạng đối số dòng lệnh hay không và thay vào đó chúng có đọc từ stdin không

Bạn dường như đang mong đợi manđọc stdin để tìm trang man mà nó sẽ hiển thị, đó sẽ là một hành vi thực sự kỳ lạ; khi nào bạn sẽ sử dụng nó? Thực tế cathiển thị stdin của nó là một tạo tác của thực tế rằng nó không làm gì khác; Tôi không nghĩ rằng bất kỳ công cụ khác hoạt động theo cách đó. Ví dụ: grepcó thể lấy tên tệp hoặc đọc từ stdinnhưng nó xử lý dữ liệu trên stdin, nó không đọc tên tệp từ stdinđó và sau đó mở nó

Nếu bạn thực sự cần hành vi này, bạn có thể sử dụng xargsđể chuyển đổi tệp thành đối số dòng lệnh:

$ xargs man < file_name

Hoặc chỉ cần nhúng một catcuộc gọi trong mancuộc gọi:

$ man $(cat file_name)

Trong bash, bạn có thể sử dụng man $(<file_name).
jordanm

Re: "Tôi không nghĩ rằng bất kỳ công cụ nào khác hoạt động theo cách đó" - Perl's (<>)trong một vòng lặp sẽ làm STDINhoặc lập luận dòng lệnh như tên tệp ...
Aaron D. Marasco

@ AaronD.Maraco Tôi có nghĩa là không có công cụ nào lấy một đối số hoặc đọc tên tệp từ stdin và đọc đối số từ tệp đó
Michael Mrozek

@MichaelMrozek Cảm ơn bạn đã làm rõ điều này. Mục đích tôi sử dụng man < file_namelà để giúp bản thân hiểu hai khái niệm này. Đọc bạn giải thích, việc thực hiện được quyết định bởi tác giả chỉ huy. Vì vậy, nếu tôi ở bên phải, các findđối số mất xử lý STDIN?
steveyang
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.