Memahami bagaimana input dikirim ke pipa di Bash

17

Saya tidak begitu mengerti bagaimana pipa bekerja di bash.

Saya tahu bahwa dibutuhkan output dari satu perintah sebagai input pada perintah lain.

Apa output yang bisa saya dapatkan karena itulah yang dicetak perintah ke layar.

Tapi bagaimana saya tahu input apa yang akan diambil perintah?

Berikut adalah contoh yang menurut saya akan berhasil:

which gem | rm

Sayangnya tidak.

Permata mana yang mencetak /usr/bin/gemsehingga harus menjadi output, kan?

Saya pikir itu diberikan kepada rm jadi itu akan terjadi rm /usr/bin/gemtetapi saya salah.

Jadi pertanyaan saya adalah, bagaimana saya tahu input apa yang diambil perintah?

ajsie
sumber
2
Terlepas dari hal lain, itu rm /usr/bin/gemadalah ide yang mengerikan . Biarkan itu gem(dan interpreter Ruby sesuai dengan itu) sendiri dan instal interpreter Ruby pilihan Anda (dan gem) menggunakan rvm: rvm.beginrescueend.com
Telemachus

Jawaban:

23

"Input" dan "argumen baris perintah" adalah hal yang berbeda.

rm menghapus file yang disediakan sebagai argumen.

Sebuah pipa mengalihkan output dari perintah tangan kiri ke input dari perintah tangan kanan. Itu tidak mempengaruhi argumen baris perintah dari program di sebelah kanan.

Untuk melakukan apa yang Anda coba lakukan, coba gunakan xargsuntuk mengkonversi input standar ke argumen baris perintah untuk menjalankan program. Itu tugasnya.

which gem | xargs rm, misalnya, akan menghapus gemdi PATH Anda.

Borealid
sumber
12

rmtidak menerima input, dibutuhkan argumen. Ini berbeda. Argumen adalah sakelar dan nama file dan sebagainya yang Anda berikan ke program pada baris perintah untuk memengaruhi perilakunya. Input adalah data tempat program bekerja. Misalnya, grepambil input dan argumen:

grep "foo" file.txt

Ada dua argumen di sana "foo"dan file.txt. The masukan adalah isi dari file.txt, bukan string file.txtitu sendiri. Karena grep mengambil input, Anda dapat menggunakannya dengan pipa:

cat file.txt | grep "foo"

menghasilkan output yang sama, karena kucing adalah mengambil file.txtsebagai argumen, dan memproduksi isi dari file.txtoutput. Keluaran itu kemudian disalurkan ke grep, memberikan efek yang sama seperti memiliki grep membuka file itu sendiri, seperti pada contoh pertama.

Jika Anda ingin menggunakan output dari satu program sebagai argumen yang lain, Anda menggunakan backticks:

rm `which gem`

atau sintaks alternatif ini (khusus bash):

rm $(which gem)

Edit: atau xargsseperti yang ditunjukkan penjawab lain. Banyak cara menguliti kucing dengan baris perintah.

Tyler McHenry
sumber
Perlu dicatat bahwa cat file.txt | grep "foo"bisa ratusan kali lebih lambat daripada grep "foo" file.txt.
Borealid
1
ini adalah bagian yang tidak saya dapatkan. bagaimana saya tahu apa argumen dan apa input standar?
ajsie
8
@ajsie: Jika Anda mengetiknya setelah nama program dan sebelum menekan enter, itu argumen. Jika Anda mengetiknya ke dalam program setelah mulai berjalan, itu adalah input standar.
Borealid
1
Mengerti! Ini menjelaskan semuanya. Sekarang saya tahu saya bisa menggunakan perintah secara langsung dan melihat apakah itu meminta saya (grep) dan saya juga bisa membaca manual (man grep) untuk melihat apakah ia menggunakan input std.
ajsie
@ajsie: Jika Anda tidak ingin masuk ke halaman manual, ada juga grep --helptinjauan umum singkat dari argumen yang diterima.
Borealid
3

Periksa manhalaman - halaman perintah yang Anda minati. Program-program ini akan menunjukkan bahwa mereka membaca dari stdin(coba man grepuntuk perintah populer yang membaca stdin).

bidadari
sumber
Saya mencoba man grep | grep 'standard input'dan menjadi If no file arguments are specified, the standard input is used.pertandingan terakhir. 👍 Saya harus memberi grepsedikit rasa obatnya sendiri. 😎
ma11hew28
2

Ini semua berbahaya untuk dijalankan jika Anda memiliki direktori di PATH Anda yang berisi ruang atau jika nama perintah berisi ruang:

rm `which gem`       # Dangerous
rm $(which gem)      # Dangerous
which gem | xargs rm # Dangerous

GNU Parallel http: // www.gnu.org/software/parallel/ tidak memiliki masalah itu, jadi ini akan berfungsi bahkan jika Anda memiliki direktori di PATH Anda yang berisi spasi atau jika nama perintah mengandung spasi:

which gem | parallel rm
parallel -a <(which bass) rm

Tonton video intro untuk GNU Parallel: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
sumber