2009-03-06 17 views
14

Khi sử dụng system() cuộc gọi trong Perl, bạn có phải thoát khỏi trình bao hệ vỏ, hoặc được thực hiện tự động không?Tôi có nên thoát khỏi các đối số vỏ trong Perl không?

Đối số sẽ là đầu vào của người dùng, vì vậy tôi muốn đảm bảo rằng đối số này không thể khai thác được.

+0

Ý anh là gì, thoát args vỏ? Bạn có nghĩa là đặt \ 's trước bất kỳ ký tự như ">" hoặc "" hoặc bạn có muốn bao gồm thoát $' s để mọi người không thể tiêm biến Perl của bạn? Hay cái gì? Đưa ra một ví dụ về ý của bạn. –

+0

Cách thêm dấu ngoặc nhọn bên trong Hệ thống cuộc gọi .... hệ thống ("$ jboss_client/subsystem = ghi/kích thước-luân phiên-tệp-xử lý = MẪU: thêm \\ (định dạng = \ {yyyy \} \\)"); Tôi luôn luôn nhận ra như dưới đây .... formatter = yyyy instaed của farmatter = {yyyy}. Bạn có thể cho tôi một IDEA để giải quyết vấn đề này không? –

Trả lời

37

Nếu bạn sử dụng system $cmd, @args thay vì system "$cmd @args" (mảng thay vì chuỗi), thì bạn không phải thoát khỏi đối số vì không có trình bao được gọi (xem system). system {$cmd} $cmd, @args sẽ không gọi một trình bao hoặc thậm chí nếu $ cmd chứa metacharacters và @args trống (điều này được ghi thành một phần của exec). Nếu các arg đến từ đầu vào của người dùng (hoặc nguồn không đáng tin cậy khác), bạn sẽ vẫn muốn hủy chúng. Xem -T trong tài liệu perlrun và tài liệu perlsec.

Nếu bạn cần đọc đầu ra hoặc gửi đầu vào cho lệnh, qxreadpipe không tương đương. Thay vào đó, hãy sử dụng open my $output, "-|", $cmd, @args hoặc open my $input, "|-", $cmd, @args mặc dù đây không phải là di động vì nó yêu cầu một số thực fork có nghĩa là chỉ Unix ... Tôi nghĩ vậy. Có lẽ nó sẽ hoạt động trên Windows với chiếc nĩa mô phỏng của nó. Một lựa chọn tốt hơn là một cái gì đó giống như IPC::Run, cũng sẽ xử lý trường hợp của các lệnh đường ống cho các lệnh khác, mà không phải là hình thức đa arg của hệ thống cũng như hình thức 4 arg mở sẽ xử lý.

+3

+1 cho cú pháp-tôi-không-chú-ý-được-thêm-tôi-không-nhận-thấy-đó. Đáng yêu. – chaos

+0

Ngoài ra, 'system {'cmd'} 'cmd'' luôn bỏ qua' sh' ngay cả khi '' cmd'' chứa các ký tự thường được diễn giải bởi trình bao. – ephemient

+0

Bạn nên thêm rằng * lý do * tại sao bạn không phải thoát khỏi các siêu ký tự shell với "system" cmd '@args "là không có shell nào được gọi trong trường hợp này (vì OP đã hỏi metachar metachars sẽ được thoát" tự động "đó không phải là trường hợp). – 8jean

14

Trên Windows, tình hình có chút khó khăn hơn. Về cơ bản, tất cả các chương trình Win32 nhận được một chuỗi dòng lệnh dài - vỏ (thường là cmd.exe) có thể thực hiện một số giải thích trước, loại bỏ các chuyển hướng <> chẳng hạn, nhưng không phải là chia nhỏ tại ranh giới từ cho chương trình. Mỗi chương trình phải tự phân tích cú pháp này (nếu họ muốn - một số chương trình không bận tâm). Trong các chương trình C và C++, các thường trình được cung cấp bởi các thư viện runtime được cung cấp với chuỗi công cụ biên dịch sẽ thường thực hiện bước phân tích cú pháp này trước khi gọi là main().

Vấn đề là, nói chung, bạn không biết cách một chương trình cụ thể sẽ phân tích cú pháp dòng lệnh. Nhiều chương trình được biên dịch với một số phiên bản của MSVC++, có quirky parsing rules are described here, nhưng nhiều chương trình khác được biên dịch với các trình biên dịch khác nhau sử dụng các quy ước khác nhau.

Điều này được kết hợp bởi thực tế là cmd.exe có quy tắc phân tích cú pháp kỳ quặc của riêng nó. Dấu mũ (^) được coi là ký tự thoát và trích dẫn ký tự sau, và văn bản bên trong dấu ngoặc kép được coi là trích dẫn nếu một danh sách các tiêu chí khéo léo được đáp ứng (xem cmd /? để biết chi tiết đầy đủ). Nếu lệnh của bạn có chứa bất kỳ ký tự lạ nào, nó rất dễ dàng cho ý tưởng của một trong những phần văn bản được trích dẫn và không được đồng bộ với chương trình đích của bạn, và tất cả các địa ngục đều bị mất.

Vì vậy, cách tiếp cận an toàn nhất cho thoát lập luận trên Windows là:

  1. luận thoát theo cách mong đợi của dòng lệnh phân tích logic của chương trình mà bạn đang gọi điện thoại. (Hy vọng bạn biết logic đó là gì, nếu không, hãy thử một vài ví dụ và đoán.)
  2. Tham gia các đối số đã thoát với dấu cách.
  3. Tiền tố mỗi ký tự không phải chữ và số của chuỗi kết quả bằng ^.
  4. Nối bất kỳ chuyển hướng hoặc thủ đoạn vỏ nào khác (ví dụ: tham gia lệnh bằng &&).
  5. Chạy lệnh bằng system() hoặc backticks.
+0

Thông tin thú vị - cảm ơn bạn. Nó không làm cho Windows trở nên khó hiểu với Unixophile này, nhưng nó giúp biết điều gì xảy ra đằng sau hậu trường. (Các trang được ref'd là một chút yên tĩnh về vai trò của caret! Nó đề cập đến nó, nhưng chỉ có ngoại lệ. Nó không phải là rõ ràng như thế nào nó xử lý^\ hoặc^", ví dụ.) –

+0

Tôi đồng ý với Jonathan Leffler. (theo ý kiến ​​của tôi) một cách khủng khiếp để xử lý các đối số dòng lệnh –

+1

Tôi hoàn toàn đồng ý rằng đó là một tình huống khủng khiếp Mặc dù công bằng, hầu hết các terribleness có thể phát sinh từ lòng sùng kính đáng kính của MS để duy trì khả năng tương thích ngược. ám ảnh họ là, hãy xem blog tuyệt vời của Raymond Chen.) –

0

Câu trả lời cho câu hỏi của bạn rất hữu ích. Cuối cùng, tôi theo lời khuyên của @ runrig nhưng sau đó sử dụng lệnh core open3() để tôi có thể thu được đầu ra từ STDERR cũng như STDOUT.

Đối với mẫu mã của open3() được sử dụng với @ runrig của giải pháp, xem câu hỏi của tôi liên quan và trả lời:
Calling system commands from Perl

1

Nếu bạn sử dụng hệ thống "$ cmd @args" (một chuỗi), sau đó bạn phải thoát khỏi các đối số vì một trình bao được gọi.

May mắn thay, đối với chuỗi trích dẫn đôi, chỉ có bốn nhân vật cần phải thoát:

" - double quote 
$ - dollar 
@ - at symbol 
\ - backslash 
+0

Tôi nghĩ OP đã nói về diễn dịch của vỏ, không tránh sự nội suy ngẫu nhiên của vô hướng và mảng. –

Các vấn đề liên quan