Apa perbedaan antara STDIN dan argumen yang diteruskan ke perintah?

16

Saya bisa menggunakan salah satu formulir untuk menjalankan catmetode:

cat file_name
cat < file_name

Hasilnya sama

Lalu saya ingin mengeksekusi mandalam formatstdin

man < file_name

Sementara file_nameberisi:

# file_name
cat

Tapi itu muncul What manual page do you want?bukannya dieksekusi man cat.

Saya ingin tahu mengapa catbisa menerima stdinsebagai argumen tetapi mantidak bisa. Dan apa perbedaan antara argumen baris perintah dan stdin?

steveyang
sumber

Jawaban:

21

Pertanyaan Anda terkait erat dengan bagaimana shell yang Anda gunakan mem-parsing input pengguna pada baris perintah.

Jika kata pertama pada baris perintah adalah program, yang terletak di folder khusus (sebagian besar ditentukan oleh PATH) dan tidak ada karakter khusus yang diberikan (tergantung dari shell yang Anda gunakan), semua kata berikutnya yang dipisahkan oleh spasi atau tab dilewatkan ke program dalam bentuk khusus yaitu array. Dengan setiap kata sebagai satu elemen dalam array.

Bagaimana programnya, Anda akan memohon interpretasi argumen (terletak di array) tergantung pada bagaimana diprogram. Ada beberapa standar kuasi tentang bagaimana sintaks dari argumen seharusnya terlihat tetapi secara umum programmer sepenuhnya bebas. Jadi argumen pertama dapat diartikan sebagai nama file atau apa pun yang dipikirkan oleh programmer pada saat ia menulis program.

Jika Anda menambahkan karakter khusus <atau >ke baris perintah Anda, shell tidak menambahkan <dan >kata-kata berikutnya ke array yang akan diteruskan ke program. Dengan <atau >diberi shell mulai membuat hal-hal mewah, didukung oleh kernel yang mendasarinya (kata kunci pipa ). Untuk memahami apa yang terjadi, Anda harus memahami apa STDINdan STDOUT(karena itu tidak terkait langsung saya hilangkan STDERR).

Semua yang terlihat Anda lihat di terminal Anda (dalam sebagian besar kasus bagian dari tampilan Anda) ditulis oleh shell atau program lain yang Anda panggil sebelumnya ke file khusus (dalam unix semuanya adalah file ). File ini memiliki id khusus dan dipanggil STDOUT. Jika suatu program ingin membaca data dari papan ketik, program itu tidak melakukan polling papan ketik secara langsung (setidaknya dalam kebanyakan kasus) tetapi membaca dari berkas khusus yang disebut STDIN. Secara internal file ini terhubung ke perangkat input standar Anda, keyboard Anda dalam banyak kasus.

Jika shell membaca <atau >dalam baris perintah yang diuraikan, ia memanipulasi STDINatau STDOUTdalam jenis tertentu untuk saat program terkait berjalan. STDINdan tidak STDOUTmenunjuk ke terminal atau perangkat input standar lagi tetapi lebih ke nama file berikutnya pada baris perintah.

Dalam hal dua garis

cat file_name
cat < file_name

perilaku yang diamati identik karena pengembang yang bersesuaian membuat catuntuk membaca data dari STDINatau membaca data dari file, yang namanya diberikan sebagai argumen baris perintah pertama (yang merupakan elemen pertama dalam larik yang dilewati shell cat). Selanjutnya cattulis seluruh konten file_nameatau STDINke terminal karena kami tidak menginstruksikan shell untuk memanipulasi STDOUT. Ingat bahwa pada baris kedua shell Anda memanipulasi STDINdengan cara ini, bahwa shell tidak mengarah ke perangkat input standar Anda lagi tetapi menunjuk ke file yang disebut file_namedi direktori kerja Anda saat ini.

Dalam kasus lain dari garis

man < file_name

mantidak dimaksudkan untuk membaca apa pun dari STDINjika dipanggil tanpa argumen yaitu array kosong. Jadi intinya

man < file_name

sama dengan

man

Misalnya manakan membaca sesuatu dari STDIN, juga jika Anda lulus -l -ke man. Dengan opsi ini diberikan pada baris perintah, Anda dapat menampilkan konten apa pun yang mandibaca dari STDINterminal Anda. Begitu

man -l - < file_name

akan bekerja juga (tapi hati-hati manbukan hanya pager tetapi juga mem-parsing input file dan konten file dan konten yang ditampilkan bisa berbeda).

Jadi bagaimana STDIN, STDOUTdan argumen baris perintah ditafsirkan semuanya terserah pengembang yang sesuai.

Saya harap jawaban saya dapat menjelaskan semuanya.

pengguna1146332
sumber
Terima kasih atas penjelasan terperinci ini. Untuk beberapa paragraf terakhir, Anda menyebutkan penggunaan man -l - < file_nameuntuk membuat manpenafsiran STDINsebagai argumen, tetapi gagal dalam sistem saya dengan STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang
Sama-sama. Tetapi saya tidak menyebutkan bahwa setidaknya versi saya man( man-db ) membaca argumen dari STDINdengan argumen yang diberikan -ldiikuti oleh -. Itu hanya menafsirkan data dari STDINsebagai halaman manual. Untuk penjelasan lebih rinci tentang argumen yang valid dan bagaimana mereka ditafsirkan, Anda harus membaca halaman manual dari program terkait. Dalam kasus Anda, konsultasikan man man. Mungkin ada opsi serupa untuk Anda man. Jika Anda ingin membaca argumen baris perintah untuk program tertentu dari STDIN xargs(seperti disebutkan di atas) adalah cara untuk pergi.
user1146332
Saya man mandan menemukan satu di OS saya tidak mendukungnya. Bagaimanapun, terima kasih atas pernyataan kedua konsep ini untuk saya.
steveyang
Saya telah mengedit jawaban Anda sehingga berisi tautan yang bermanfaat dan bukan lmgtfy. Memposting tautan lmgtfy adalah 1) kasar, 2) tidak membantu dan 3) sangat disukai di situs SE. Entah memberikan tautan atau tidak, tetapi jika Anda memilih untuk melakukannya, berikan tautan ke informasi aktual dan bukan dengan cara sarkastik untuk menunjukkan kepada seseorang cara menemukannya.
terdon
12

Mereka sangat berbeda. Argumen baris perintah dilewatkan ke program dalam array dan ia dapat melakukan apa yang diinginkannya; stdin adalah aliran input dari program untuk meminta data. Program yang memproses file sering memilih untuk mendukung keduanya, tetapi mereka harus melakukannya secara manual - mereka memeriksa apakah nama file dilewatkan sebagai argumen baris perintah, dan jika tidak mereka membaca dari stdin sebagai gantinya

Anda tampaknya mengharapkan manuntuk membaca stdin untuk menemukan halaman manual yang seharusnya ditampilkan, yang akan menjadi perilaku yang sangat aneh; kapan kamu akan menggunakannya? Fakta yang catmenampilkan stdin adalah artefak dari fakta bahwa ia tidak melakukan hal lain; Saya tidak berpikir alat lain bekerja seperti itu. Misalnya, grepdapat mengambil nama file atau membaca dari stdin, tetapi memproses data stdin, tidak membaca nama file dari stdindan kemudian membukanya

Jika Anda benar-benar membutuhkan perilaku ini, Anda bisa menggunakan xargs, yang mengkonversi file ke argumen baris perintah:

$ xargs man < file_name

Atau hanya menyematkan catpanggilan dalam manpanggilan:

$ man $(cat file_name)
Michael Mrozek
sumber
Di bash, Anda bisa menggunakan man $(<file_name).
jordanm
Re: "Saya tidak berpikir alat lain bekerja seperti itu" - Perl (<>)dalam satu lingkaran akan melakukan STDINatau argumen baris perintah sebagai nama file ...
Aaron D. Marasco
@ AaronD.Marasco Maksud saya tidak ada alat yang mengambil argumen atau membaca nama file dari stdin dan membaca argumen dari file itu
Michael Mrozek
@MichaelMrozek Terima kasih atas klarifikasi ini. Tujuan yang saya gunakan man < file_nameadalah untuk membantu diri saya memahami dua konsep ini. Membaca penjelasan Anda, implementasi diputuskan oleh penulis perintah. Jadi jika saya di bawah kanan, findargumen yang dibutuhkan agak memproses STDIN?
steveyang