Ruby ความแตกต่างระหว่าง exec ระบบและ% x () หรือ Backticks


370

ความแตกต่างระหว่างวิธีการทับทิมต่อไปนี้คืออะไร?

exec, systemและ%x()หรือBackticks

ฉันรู้ว่ามันถูกใช้เพื่อรันคำสั่งเทอร์มินัลผ่านทางการเขียนโปรแกรมผ่าน Ruby แต่ฉันต้องการรู้ว่าทำไมมีสามวิธีที่แตกต่างกันในการทำเช่นนี้


1
คำสั่งเหล่านี้และอื่น ๆ อีกมากมายมีการอธิบายค่อนข้างดีในเอกสาร: exec ระบบ backticks
Zetetic

1
: มีดีบทความทับทิม QuickTips ในหัวข้อที่เป็นดำเนินการคำสั่งเชลล์
Simon Perepelitsa

6
เนื่องจากมีคนเพิ่งขุดหัวข้อเก่านี้ "การทำงานกับกระบวนการ Unix" เป็นหนังสือที่ยอดเยี่ยมสำหรับ Rubyists สนใจในหัวข้อ: workingwithunixprocesses.com
Michael Kohl

1
shฉันไม่มีใครแปลกใจในคำตอบที่กล่าวถึง
เดนนิส

@Dennis เมื่อฉันเพิ่มคำถามนี้ทับทิม 1.9.3 * ไม่ออก
นายแบล็

คำตอบ:


411

ระบบ

systemวิธีการเรียกโปรแกรมระบบ คุณต้องให้คำสั่งเป็นอาร์กิวเมนต์สตริงกับวิธีนี้ ตัวอย่างเช่น:

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

โปรแกรมเรียกจะใช้ในปัจจุบันSTDIN, STDOUTและSTDERRวัตถุของโปรแกรมทับทิมของคุณ ในความเป็นจริงค่าตอบแทนที่เกิดขึ้นจริงเป็นอย่างใดอย่างหนึ่งtrue, หรือfalse nilในตัวอย่างวันที่ถูกตีพิมพ์ผ่านวัตถุ IO STDINของ เมธอดจะส่งคืนtrueหากกระบวนการออกจากสถานะเป็นศูนย์falseหากกระบวนการออกจากสถานะไม่เป็นศูนย์และnilหากการดำเนินการล้มเหลว

ผลข้างเคียงก็คือตัวแปรทั่วโลก$?ถูกตั้งค่าเป็นProcess::Statusวัตถุ วัตถุนี้จะมีข้อมูลเกี่ยวกับการเรียกตัวเองรวมถึงตัวระบุกระบวนการ (PID) ของกระบวนการที่เรียกใช้และสถานะการออก

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

backticks

Backticks (``) เรียกโปรแกรมระบบและส่งคืนผลลัพธ์ ซึ่งแตกต่างจากวิธีแรกคำสั่งไม่ได้ให้ผ่านสตริง แต่โดยการวางไว้ในคู่ backticks

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

ตัวแปรโกลบอล$?ถูกตั้งค่าผ่าน backticks ด้วย ด้วย backticks คุณยังสามารถใช้การแก้ไขสตริงด้วย

% x ()

การใช้%xเป็นทางเลือกของสไตล์ backticks มันจะส่งคืนผลลัพธ์เช่นกัน เช่นเดียวกับญาติ%wและ%q(ในกลุ่มอื่น ๆ ) ตัวคั่นใด ๆ จะพอเพียงตราบเท่าที่ตัวคั่นลักษณะวงเล็บเหลี่ยมตรงกัน วิธีนี้%x(date), %x{date}และ%x-date-มีความหมายเหมือนกันทั้งหมด เช่นเดียวกับ backticks %xสามารถใช้การแก้ไขสตริงได้

exec

โดยใช้Kernel#execกระบวนการปัจจุบัน (สคริปต์ทับทิมของคุณ) execจะถูกแทนที่ด้วยกระบวนการเรียกใช้ผ่าน วิธีการสามารถใช้สตริงเป็นอาร์กิวเมนต์ ในกรณีนี้สตริงจะขึ้นอยู่กับการขยายตัวของเชลล์ เมื่อใช้มากกว่าหนึ่งอาร์กิวเมนต์อาร์กิวเมนต์แรกจะถูกใช้เพื่อเรียกใช้งานโปรแกรมและต่อไปนี้ถูกจัดเตรียมไว้เป็นอาร์กิวเมนต์ของโปรแกรมที่จะเรียกใช้

Open3.popen3

บางครั้งข้อมูลที่ต้องการถูกเขียนไปยังอินพุตมาตรฐานหรือข้อผิดพลาดมาตรฐานและคุณต้องควบคุมสิ่งเหล่านั้นด้วย Open3.popen3มาที่นี่มีประโยชน์:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end

3
และสำหรับการควบคุมมากขึ้นเม็ดเล็กของวิธีการจับโทรSTDIN, STDOUT, STDERRพิจารณาOpen3.popen3แทน; เช่นดูstackoverflow.com/a/10922097/258662
cboettig

1
ขอบคุณที่กล่าวถึงว่า backticks สนับสนุนการแก้ไขสตริงซึ่งแก้ไขปัญหาของฉันได้
adg

244

นี่คือแผนผังลำดับงานตามคำตอบนี้ ดูยังใช้scriptที่จะเลียนแบบขั้ว

ป้อนคำอธิบายรูปภาพที่นี่


3
มันไม่ง่ายเลย ในกรณีของฉันมัน "ก็โอเค (และต้อง) เพื่อบล็อกจนกว่ากระบวนการจะเสร็จสมบูรณ์" เพื่อใช้ popen3 เพื่อตรวจสอบเอาต์พุต STDOUT / STDERR
Nakilon

คุณสามารถทำให้การบล็อกที่ไม่มีการบล็อกไปยังบล็อก (อย่างมีประสิทธิภาพ) โดยการล้อมรอบในขณะที่ คุณไม่สามารถทำการบล็อกการโทรเป็นการโทรที่ไม่บล็อคได้อย่างง่ายดาย
เอียน

106

พวกเขาทำสิ่งต่าง ๆ execแทนที่กระบวนการปัจจุบันด้วยกระบวนการใหม่และไม่กลับมา systemเรียกใช้กระบวนการอื่นและส่งคืนค่าการออกเป็นกระบวนการปัจจุบัน การใช้ backticks จะเรียกใช้กระบวนการอื่นและส่งกลับผลลัพธ์ของกระบวนการนั้นไปยังกระบวนการปัจจุบัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.