Ruby থেকে শেল কমান্ড কল




shell interop (14)

রুবি প্রোগ্রামের ভিতর থেকে আমি কিভাবে শেল কমান্ডগুলি কল করব? তাহলে কিভাবে আমি রুবিতে এই কমান্ডগুলি থেকে আউটপুট পেতে পারি?


আপনি ব্যাকলিক অপারেটর (`) ব্যবহার করতে পারেন, পার্লের মতো:

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

আপনি যদি কিছু সহজ প্রয়োজন।

আপনি কোন পদ্ধতিটি ব্যবহার করতে চান তা নির্ভর করে আপনি যা অর্জন করতে চান তা নির্ভর করে; বিভিন্ন পদ্ধতি সম্পর্কে আরো বিস্তারিত জানার জন্য ডক্স চেক করুন।


আমরা একাধিক উপায়ে এটি অর্জন করতে পারেন।

Kernel#exec ব্যবহার করে, এই কমান্ডের পরে কিছুই কার্যকর করা হয় নি:

exec('ls ~')

backticks or %x ব্যবহার করে

`ls ~`
=> "Applications\nDesktop\nDocuments"
%x(ls ~)
=> "Applications\nDesktop\nDocuments"

Kernel#system কমান্ড ব্যবহার করে সফল হলে true ফিরিয়ে দেয়, ব্যর্থ হলে false ব্যর্থ হয় এবং কমান্ড কার্যকর ব্যর্থ হলে ব্যর্থ হয়:

system('ls ~')
=> true

আমি স্পষ্টভাবে রুবি বিশেষজ্ঞ নই, কিন্তু আমি এটি একটি শট দিতে হবে:

$ irb 
system "echo Hi"
Hi
=> true

আপনি এমন কিছু করতে সক্ষম হবেন:

cmd = 'ls'
system(cmd)

আরও একটি বিকল্প:

যখন তুমি:

  • stderr পাশাপাশি stdout প্রয়োজন
  • ওপেন 3 / ওপেন 4 ব্যবহার করতে পারে না (তারা আমার ম্যাকের নেটবায়ানে ব্যতিক্রমগুলি নিক্ষেপ করে, কোন ধারণা নেই কেন)

আপনি শেল পুনঃনির্দেশ ব্যবহার করতে পারেন:

puts %x[cat bogus.txt].inspect
  => ""

puts %x[cat bogus.txt 2>&1].inspect
  => "cat: bogus.txt: No such file or directory\n"

এমএস-ডস এর প্রথম দিক থেকে Linux , ম্যাক এবং Windows জুড়ে 2>&1 সিনট্যাক্স কাজ করে।


এই পদ্ধতিগুলির মধ্যে নির্বাচন করার সময় কিছু বিষয় চিন্তা করতে হয়:

  1. আপনি শুধু stdout চান বা আপনি stderr হিসাবে ভাল প্রয়োজন? অথবা এমনকি পৃথক?
  2. আপনার আউটপুট কত বড়? আপনি মেমরির মধ্যে পুরো ফলাফল রাখা চান?
  3. উপপ্রয়োগ এখনও চলমান যখন আপনি আপনার আউটপুট কিছু পড়তে চান?
  4. আপনি ফলাফল কোড প্রয়োজন?
  5. আপনি একটি Ruby বস্তুর প্রয়োজন যা প্রক্রিয়া প্রতিনিধিত্ব করে এবং আপনি দাবিতে এটি হত্যা করতে দেয়?

আপনাকে সহজ ব্যাক্টিক্স (``), সিস্টেম (), এবং IO.popen থেকে IO.pipe এবং IO.select সহ সম্পূর্ণ-ফুটে থাকা Kernel.fork / Kernel.exec থেকে কিছু প্রয়োজন হতে পারে।

একটি উপ-প্রসেস কার্যকর করার জন্য খুব বেশি সময় লাগলে আপনি সময়সীমার মিশ্রণে নিক্ষেপ করতেও পারেন।

দুর্ভাগ্যবশত, এটা অনেক নির্ভর করে


এই ব্যাখ্যা আমার একটি বন্ধু থেকে রুবি স্ক্রিপ্ট মন্তব্য উপর ভিত্তি করে। আপনি যদি স্ক্রিপ্টটি উন্নত করতে চান তবে লিঙ্কটিতে এটি আপডেট করুন।

প্রথমত, মনে রাখবেন যে রুবি যখন একটি শেলে ফোন করে, তখন সাধারণত এটি /bin/sh কল নয়, বাশ নয় । কিছু বাশ সিনট্যাক্স সব সিস্টেমে /bin/sh দ্বারা সমর্থিত নয়।

শেল স্ক্রিপ্ট চালানোর উপায় এখানে দেওয়া হল:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , সাধারণত ব্যাক্টিক্স `cmd` বলা হয়

    এটি বাশ, পিএইচপি এবং পার্ল সহ অন্যান্য অনেক ভাষার মতো।

    শেল কমান্ডের ফলাফল প্রদান করে।

    ডক্স: http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
  2. বিল্ট ইন সিনট্যাক্স, %x( cmd )

    x চরিত্রটি অনুসরণ করে একটি ডিলিমিটার যা কোনও অক্ষর হতে পারে। যদি ডিলিমিটার অক্ষরগুলির মধ্যে একটি হয় ( , [ , { , বা < , আক্ষরিক মিলযুক্ত বন্ধকী ডিলিমিটার পর্যন্ত অক্ষরগুলি ধারণ করে, নেস্টেড ডিলিমিটার জোড়াগুলির অ্যাকাউন্ট গ্রহণ করে। অন্যান্য সমস্ত বিভ্রান্তিকরদের জন্য, আক্ষরিক অক্ষরের মধ্যে রয়েছে ডেলিমিটার চরিত্রের পরবর্তী ঘটনা। স্ট্রিং ইন্টারপোলেশন #{ ... } এর অনুমতি দেওয়া হয়।

    শট কমান্ডের ফলাফলটি, ব্যাকটিক্সের মতই ফিরে আসে।

    ডক্স: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

    value = %x( echo 'hi' )
    value = %x[ #{cmd} ]
  3. Kernel#system

    একটি subshell মধ্যে প্রদত্ত কমান্ড Executes।

    কমান্ড পাওয়া যায় এবং সফলভাবে দৌড়ে true ফেরত, অন্যথায় false

    ডক্স: http://ruby-doc.org/core/Kernel.html#method-i-system

    wasGood = system( "echo 'hi'" )
    wasGood = system( cmd )
  4. Kernel#exec

    প্রদত্ত বাহ্যিক কমান্ড চালানোর দ্বারা বর্তমান প্রক্রিয়া প্রতিস্থাপন করে।

    কেউ ফেরত দেয় না, বর্তমান প্রক্রিয়া প্রতিস্থাপিত হয় এবং অবিরত না।

    ডক্স: http://ruby-doc.org/core/Kernel.html#method-i-exec

    exec( "echo 'hi'" )
    exec( cmd ) # Note: this will never be reached because of the line above

এখানে কিছু অতিরিক্ত পরামর্শ আছে: $? , যা $CHILD_STATUS মত একই, আপনি যদি ব্যাটিক্স, system() বা %x{} ব্যবহার করেন তবে শেষ সিস্টেমটি চালিত কমান্ডের স্থিতিটি অ্যাক্সেস করে। তারপর আপনি exitstatus এবং exitstatus বৈশিষ্ট্য অ্যাক্সেস করতে পারেন:

$?.exitstatus

আরও পড়ার জন্য দেখুন:


এখানে উত্তরগুলি ব্যবহার করে এবং মিহাইয়ের উত্তরে লিঙ্ক করা হয়েছে, আমি এমন একটি ফাংশন রেখেছি যা এই প্রয়োজনীয়তা পূরণ করে:

  1. নিখুঁতভাবে STDOUT এবং STDERR captures তাই তারা আমার স্ক্রিপ্ট কনসোল থেকে চালানো হয় যখন "লিক" না।
  2. একটি অ্যারে হিসাবে শেল পাস করা আর্গুমেন্ট অনুমতি দেয়, তাই পালানোর বিষয়ে চিন্তা করার কোন প্রয়োজন নেই।
  3. কমান্ডের প্রস্থান অবস্থা ক্যাপচার করে যাতে একটি ত্রুটি ঘটেছে তা স্পষ্ট।

বোনাস হিসাবে, শেল কমান্ড সাফল্যের সাথে (0) আউট হয়ে STDOUT এ কিছু রাখে এমন ক্ষেত্রে সেগুলি STDOUT এও ফেরত দেবে। এই পদ্ধতিতে, এটি system থেকে পৃথক, যা কেবল এই ক্ষেত্রে true ফেরত দেয়।

কোড অনুসরণ করে। নির্দিষ্ট ফাংশন system_quietly :

require 'open3'

class ShellError < StandardError; end

#actual function:
def system_quietly(*cmd)
  exit_status=nil
  err=nil
  out=nil
  Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
    err = stderr.gets(nil)
    out = stdout.gets(nil)
    [stdin, stdout, stderr].each{|stream| stream.send('close')}
    exit_status = wait_thread.value
  end
  if exit_status.to_i > 0
    err = err.chomp if err
    raise ShellError, err
  elsif out
    return out.chomp
  else
    return true
  end
end

#calling it:
begin
  puts system_quietly('which', 'ruby')
rescue ShellError
  abort "Looks like you don't have the `ruby` command. Odd."
end

#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/ruby"

এখানে এই উত্তর উপর ভিত্তি করে একটি প্রবাহচিহ্ন। একটি টার্মিনাল অনুকরণ করতে script ব্যবহার করে , এছাড়াও দেখুন।


নির্দিষ্ট কমান্ডটি চালানোর জন্য একটি পটভূমি প্রক্রিয়া তৈরি করতে spawn কমান্ডটি ভুলবেন না। Process ক্লাস এবং ফিরতি pid ব্যবহার করে আপনি এটির সমাপ্তির জন্য অপেক্ষা করতে পারেন:

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

ডক বলেছেন: এই পদ্ধতিটি #system অনুরূপ কিন্তু কমান্ডটি শেষ করার জন্য অপেক্ষা করে না।


যদি আপনার সাধারণ ক্ষেত্রে তুলনায় আরো জটিল কেস থাকে (যা `` সাথে পরিচালনা করা যায় না) তাহলে here Kernel.spawn()Kernel.spawn() । এই বহিরাগত কমান্ড চালানোর জন্য স্টক রুবি দ্বারা উপলব্ধ সবচেয়ে জেনেরিক / পূর্ণ বৈশিষ্ট্যযুক্ত হতে বলে মনে হয়।

যেমন আপনি এটি ব্যবহার করতে পারেন:

  • প্রক্রিয়া গ্রুপ তৈরি করুন (উইন্ডোজ)
  • পুনঃনির্দেশ, আউট, ফাইল / প্রতিটি অন্যান্য ত্রুটি।
  • সেট Env ওয়ার, ইউমাস
  • আদেশ execution আগে dir পরিবর্তন
  • CPU / তথ্য / জন্য সম্পদ সীমা সেট করুন ...
  • অন্যান্য উত্তর অন্যান্য বিকল্পের সাথে সম্পন্ন করা যেতে পারে সবকিছু, কিন্তু আরো কোড দিয়ে।

অফিসিয়াল here যথেষ্ট যথেষ্ট উদাহরণ আছে।

env: hash
  name => val : set the environment variable
  name => nil : unset the environment variable
command...:
  commandline                 : command line string which is passed to the standard shell
  cmdname, arg1, ...          : command name and one or more arguments (no shell)
  [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
  clearing environment variables:
    :unsetenv_others => true   : clear environment variables except specified by env
    :unsetenv_others => false  : dont clear (default)
  process group:
    :pgroup => true or 0 : make a new process group
    :pgroup => pgid      : join to specified process group
    :pgroup => nil       : dont change the process group (default)
  create new process group: Windows only
    :new_pgroup => true  : the new process is the root process of a new process group
    :new_pgroup => false : dont create a new process group (default)
  resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
    :rlimit_resourcename => limit
    :rlimit_resourcename => [cur_limit, max_limit]
  current directory:
    :chdir => str
  umask:
    :umask => int
  redirection:
    key:
      FD              : single file descriptor in child process
      [FD, FD, ...]   : multiple file descriptor in child process
    value:
      FD                        : redirect to the file descriptor in parent process
      string                    : redirect to file with open(string, "r" or "w")
      [string]                  : redirect to file with open(string, File::RDONLY)
      [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
      [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
      [:child, FD]              : redirect to the redirected file descriptor
      :close                    : close the file descriptor in child process
    FD is one of follows
      :in     : the file descriptor 0 which is the standard input
      :out    : the file descriptor 1 which is the standard output
      :err    : the file descriptor 2 which is the standard error
      integer : the file descriptor of specified the integer
      io      : the file descriptor specified as io.fileno
  file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
    :close_others => false : inherit fds (default for system and exec)
    :close_others => true  : dont inherit (default for spawn and IO.popen)

যেভাবে আমি এটি করতে চাই তা %x আক্ষরিক ব্যবহার করে, যা কমান্ডের উদ্ধৃতি ব্যবহার করার জন্য এটি সহজ (এবং পাঠযোগ্য!) করে তোলে, যেমন:

directorylist = %x[find . -name '*test.rb' | sort]

যা, এই ক্ষেত্রে, বর্তমান ডিরেক্টরিের অধীনে সমস্ত পরীক্ষা ফাইলগুলির সাথে ফাইল তালিকা তৈরি করবে, যা আপনি প্রত্যাশিত হিসাবে প্রক্রিয়া করতে পারেন:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end

রুবিতে শেল স্ক্রিপ্টগুলি চালানোর বিষয়ে আমার মতামতটি সেরা নিবন্ধটি এখানে রয়েছে: " http://tech.natemurray.com/2007/03/ruby-shell-commands.html "।

আপনি শুধুমাত্র আউটপুট ব্যবহার ব্যাকটিক্স পেতে প্রয়োজন হলে।

আমি STDOUT এবং STDERR এর মত আরো উন্নত জিনিস প্রয়োজন তাই আমি Open4 মণি ব্যবহার। আপনি সেখানে ব্যাখ্যা সব পদ্ধতি আছে।


সবচেয়ে সহজ উপায়, উদাহরণস্বরূপ:

reboot = `init 6`
puts reboot

  • ব্যাকটিকস পদ্ধতি রুবি থেকে শেল কমান্ডগুলি কল করার সবচেয়ে সহজ উপায়। এটি শেল কমান্ডের ফলাফল প্রদান করে।

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`




interop