Ruby, Perbedaan antara exec, sistem dan% x () atau Backticks

370

Apa perbedaan antara metode Ruby berikut?

exec, systemdan %x()atau Backticks

Saya tahu mereka digunakan untuk menjalankan perintah terminal secara pemrograman melalui Ruby, tetapi saya ingin tahu mengapa ada tiga cara berbeda untuk melakukan ini.

Tuan hitam
sumber
1
Perintah-perintah ini, dan banyak lainnya, dijelaskan dengan sangat baik dalam dokumen: backticks sistem exec
zetetic
1
Ada artikel Quicktips Ruby yang bagus tentang topik itu: Jalankan perintah shell .
Simon Perepelitsa
6
Karena seseorang baru saja menggali utas lama ini, "Bekerja Dengan Proses Unix" adalah buku yang sangat bagus untuk para Rubyists yang tertarik dengan topik: workingwithunixprocesses.com
Michael Kohl
1
Saya terkejut tidak ada jawaban yang menyebutkan sh.
Dennis
@ Dennis Ketika saya mengajukan pertanyaan ini ruby ​​1.9.3 * tidak dirilis.
Tn. Black

Jawaban:

411

sistem

The systempemanggilan metode program sistem. Anda harus memberikan perintah sebagai argumen string untuk metode ini. Sebagai contoh:

>> system("date")
Wed Sep 4 22:03:44 CEST 2013
=> true

Program yang dipanggil akan menggunakan objek saat ini STDIN, STDOUTdan STDERRobjek dari program Ruby Anda. Bahkan, nilai pengembalian aktualnya adalah true, falseatau nil. Dalam contoh tanggal dicetak melalui objek IO dari STDIN. Metode akan kembali truejika proses keluar dengan status nol, falsejika proses keluar dengan status tidak-nol dan niljika eksekusi gagal.

Efek samping lain adalah bahwa variabel global $?diatur ke Process::Statusobjek. Objek ini akan berisi informasi tentang panggilan itu sendiri, termasuk pengidentifikasi proses (PID) dari proses yang dipanggil dan status keluar.

>> system("date")
Wed Sep 4 22:11:02 CEST 2013
=> true
>> $?
=> #<Process::Status: pid 15470 exit 0>

Backticks

Backticks (``) memanggil program sistem dan mengembalikan hasilnya. Berbeda dengan pendekatan pertama, perintah tidak diberikan melalui string, tetapi dengan meletakkannya di dalam pasangan backticks.

>> `date`
=> Wed Sep 4 22:22:51 CEST 2013   

Variabel global $?diatur melalui backticks juga. Dengan backticks Anda juga dapat menggunakan interpolasi string.

% x ()

Menggunakan %xadalah alternatif dari gaya backticks. Ini akan mengembalikan output juga. Seperti kerabatnya %wdan %q(antara lain), pembatas apa pun akan mencukupi selama pembatas braket cocok. Ini berarti %x(date), %x{date}dan %x-date-semuanya adalah sinonim. Seperti backticks %xdapat menggunakan interpolasi string.

eksekutif

Dengan menggunakan Kernel#execproses saat ini (skrip Ruby Anda) diganti dengan proses yang diminta exec. Metode ini dapat mengambil string sebagai argumen. Dalam hal ini string akan mengalami ekspansi shell. Ketika menggunakan lebih dari satu argumen, maka yang pertama digunakan untuk menjalankan suatu program dan berikut ini disediakan sebagai argumen untuk program yang akan dipanggil.

Open3.popen3

Terkadang informasi yang diperlukan ditulis ke input standar atau kesalahan standar dan Anda perlu mengontrolnya juga. Ini Open3.popen3berguna:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end
Konrad Reiche
sumber
3
Dan untuk lebih banyak kontrol fine-grained bagaimana menangani panggilan STDIN, STDOUT, STDERR, pertimbangkan Open3.popen3bukan; mis. lihat stackoverflow.com/a/10922097/258662
cboettig
1
Terima kasih telah menyebutkan bahwa backticks mendukung interpolasi string yang menyelesaikan masalah saya.
adg
244

Berikut bagan alur berdasarkan jawaban ini . Lihat juga, gunakan scriptuntuk meniru terminal .

masukkan deskripsi gambar di sini

Ian
sumber
3
Ini tidak sesederhana itu. Dalam kasus saya itu "OK (dan perlu) untuk memblokir sampai proses selesai" untuk kemudian menggunakan popen3 untuk memeriksa output STDOUT / STDERR.
Nakilon
Anda selalu dapat menyebabkan panggilan non-pemblokiran untuk (secara efektif) memblokir dengan membungkusnya dalam loop sementara. Anda tidak dapat membuat panggilan pemblokiran menjadi panggilan yang tidak menghalangi dengan mudah.
Ian
106

Mereka melakukan hal yang berbeda. execmengganti proses saat ini dengan proses baru dan tidak pernah kembali . systemmeminta proses lain dan mengembalikan nilai keluarnya ke proses saat ini. Menggunakan backticks memanggil proses lain dan mengembalikan output dari proses itu ke proses saat ini.

William Pursell
sumber