Tôi biết đây là một chuỗi cũ, nhưng có một tùy chọn khác đã được chạm nhẹ vào bởi Simon Hürlimann.
Không có nhiều thông tin về chủ đề này và tôi nghĩ điều này có thể giúp những người khác có nhu cầu.
Ví dụ này, chúng ta sẽ sử dụng Open3
mang đến cho bạn khả năng để chạy các lệnh đồng bộ hoặc không đồng bộ, và cung cấp stdout, stderr, mã thoát và PID.
Open3 cấp cho bạn quyền truy cập vào stdout, stderr, mã thoát và chuỗi để chờ quá trình con khi chạy chương trình khác. Bạn có thể chỉ định các thuộc tính khác nhau, chuyển hướng, thư mục hiện tại, vv, của chương trình theo cách tương tự như đối với Process.spawn. (Nguồn: Open3 Docs)
Tôi đã chọn định dạng đầu ra thành đối tượng CommandStatus
. Điều này chứa stdout
, stderr
, pid
(của chủ đề công nhân) và exitstatus
.
class Command
require 'open3'
class CommandStatus
@stdout = nil
@stderr = nil
@pid = nil
@exitstatus = nil
def initialize(stdout, stderr, process)
@stdout = stdout
@stderr = stderr
@pid = process.pid
@exitstatus = process.exitstatus
end
def stdout
@stdout
end
def stderr
@stderr
end
def exit_status
@exitstatus
end
def pid
@pid
end
end
def self.execute(command)
command_stdout = nil
command_stderr = nil
process = Open3.popen3(ENV, command + ';') do |stdin, stdout, stderr, thread|
stdin.close
stdout_buffer = stdout.read
stderr_buffer = stderr.read
command_stdout = stdout_buffer if stdout_buffer.length > 0
command_stderr = stderr_buffer if stderr_buffer.length > 0
thread.value # Wait for Process::Status object to be returned
end
return CommandStatus.new(command_stdout, command_stderr, process)
end
end
cmd = Command::execute("echo {1..10}")
puts "STDOUT: #{cmd.stdout}"
puts "STDERR: #{cmd.stderr}"
puts "EXIT: #{cmd.exit_status}"
Trong khi đọc bộ đệm STDOUT/ERR, tôi sử dụng command_stdout = stdout_buffer if stdout_buffer.length > 0
để kiểm soát xem các biến command_stdout
được gán hay không. Bạn nên vượt qua nil
thay vì ""
khi không có dữ liệu. Nó rõ ràng hơn khi bàn giao dữ liệu sau này.
Bạn có thể nhận thấy tôi sử dụng command + ';'
. Lý do cho điều này được dựa trên tài liệu từ Kernel.exec (Đó là những gì popen3 sử dụng):
Nếu chuỗi từ hình thức đầu tiên (exec ("lệnh")) sau những quy tắc đơn giản:
- không có ký tự meta
- không vỏ từ dành riêng và không đặc biệt được xây dựng trong
- của Ruby gọi lệnh trực tiếp mà không cần vỏ
Bạn có thể bắt buộc trình bao bằng cách thêm ";" vào chuỗi (vì ";" là một nhân vật meta)
này chỉ ngăn một Ruby từ ném một lỗi 'spawn': No such file or directory
nếu bạn vượt qua một lệnh bị thay đổi. Thay vào đó nó sẽ truyền nó thẳng đến hạt nhân, nơi lỗi sẽ được giải quyết một cách duyên dáng và xuất hiện như là STDERR thay vì một ngoại lệ chưa được bắt.
vì vậy, giả sử nếu tôi tiếp xúc với lớp này, hoàn toàn chưa được lọc (tôi sẽ không) cho người dùng cuối và họ đã cung cấp băm bóng và sau đó "tên người dùng; rm -rf /" làm tên người dùng - điều này sẽ không có tác dụng xóa bỏ '/' – arbales
đúng. Các đối số được truyền trực tiếp đến chương trình đã thực hiện. Bạn có thể tự mình xác minh điều này. Hãy thử chạy hệ thống 'ruby -e' * W (ls -l foo; rm-rf /) '' – cam
à, thật tuyệt. Nó có ý nghĩa hoàn hảo. Tôi nghĩ rằng tôi có suy nghĩ này để đảm bảo một ứng dụng được an toàn phải tự nhiên khó hơn nó, khó hơn các bước đơn giản và sự kiện, như thể tồn tại một trường hợp nguy hiểm cho mọi thứ.Điều này có thể vì tôi chưa bao giờ đọc/học được nhiều về nó. – arbales