2009-07-07 34 views
11

Tôi đang viết một mô-đun perl có tên là perl5i. Mục đích của nó là để sửa chữa một loạt các vấn đề thường gặp của Perl trong một mô-đun (sử dụng nhiều mô-đun khác).Viết trình bao bọc dòng lệnh di động trong C

Để gọi nó trên dòng lệnh cho một dòng bạn muốn viết: perl -Mperl5i -e 'say "Hello"' Tôi nghĩ rằng đó là quá dài dòng vì vậy tôi muốn cung cấp một wrapper perl5i để bạn có thể viết perl5i -e 'say "Hello"'. Tôi cũng muốn mọi người có thể viết kịch bản với #!/usr/bin/perl5i vì vậy nó phải là một chương trình C biên dịch.

Tôi đã tìm tất cả những gì tôi phải làm là đẩy "-Mperl5i" lên phía trước danh sách đối số và gọi perl. Và đó là những gì tôi đã thử.

#include <unistd.h> 
#include <stdlib.h> 

/* 
* Meant to mimic the shell command 
*  exec perl -Mperl5i "[email protected]" 
* 
* This is a C program so it works in a #! line. 
*/ 

int main (int argc, char* argv[]) { 
    int i; 
    /* This value is set by a program which generates this C file */ 
    const char* perl_cmd = "/usr/local/perl/5.10.0/bin/perl"; 
    char* perl_args[argc+1]; 
    perl_args[0] = argv[0]; 
    perl_args[1] = "-Mperl5i"; 

    for(i = 1; i <= argc; i++) { 
     perl_args[i+1] = argv[i]; 
    } 

    return execv(perl_cmd, perl_args); 
} 

Windows làm phức tạp phương pháp này. Rõ ràng các chương trình trong Windows không được thông qua một mảng các đối số, chúng được chuyển tất cả các đối số dưới dạng một chuỗi duy nhất và sau đó thực hiện phân tích cú pháp của riêng chúng! Vì vậy, một cái gì đó như perl5i -e "say 'Hello'" trở thành perl -Mperl5i -e say 'Hello' và Windows không thể xử lý việc thiếu trích dẫn.

Vì vậy, làm cách nào tôi có thể xử lý việc này? Gói tất cả mọi thứ trong dấu ngoặc kép và thoát trên Windows? Có thư viện để xử lý điều này cho tôi không? Có cách tiếp cận tốt hơn không? Tôi có thể không chỉ tạo ra một chương trình C trên Windows và viết nó như là một wrapper perl vì nó không hỗ trợ #! dù sao?

CẬP NHẬT: Hãy rõ ràng hơn, đây là phần mềm được vận chuyển để các giải pháp yêu cầu sử dụng một trình bao hoặc tinh chỉnh cấu hình vỏ (ví dụ: alias perl5i='perl -Mperl5i') không thỏa đáng.

Trả lời

3

Đối với Windows, sử dụng một tập tin thực thi.

perl5i.bat

@echo off 
perl -Mperl5i %* 

%* là tất cả các thông số dòng lệnh trừ %0.

Trên hệ thống Unixy, một tập lệnh shell tương tự sẽ đủ.

Cập nhật:

Tôi nghĩ rằng đây sẽ làm việc, nhưng tôi không có phù thủy vỏ và tôi không có một hệ thống * nix tiện để kiểm tra.

perl5i

#!bash 

perl -Mperl5i [email protected] 

Cập nhật lần nữa:

DUH! Bây giờ tôi đã hiểu chính xác số #! của bạn. Kịch bản lệnh shell của tôi sẽ hoạt động từ CLI nhưng không hoạt động trong dòng #!, kể từ #!foo requries rằng foo là tệp nhị phân.

Bỏ qua cập nhật trước đó.

Dường như Windows làm phức tạp mọi thứ. Tôi nghĩ tốt nhất của bạn là sử dụng một tập tin thực thi.

Bạn có thể use a file association, liên kết .p5i với perl -Mperl5i %*. Tất nhiên điều này có nghĩa là mucking về trong registry, tốt nhất là tránh IMO. Tốt hơn nên bao gồm các hướng dẫn về cách thêm liên kết theo cách thủ công vào tài liệu của bạn.

Tuy nhiên, một bản cập nhật

Bạn có thể muốn xem xét cách parl hiện nó.

+1

Cảm ơn, tôi có thể chỉ cần punt và sử dụng một tập tin thực thi cho Windows. Một kịch bản shell sẽ không đủ cho Unix vì #! sẽ chỉ tôn vinh các chương trình biên soạn. – Schwern

+3

Tuy nhiên, một nhược điểm đối với các tệp hàng loạt trên Windows -^C-ing ra khỏi tập lệnh theo lô sẽ gây ra lời nhắc "Chấm dứt tiến trình hàng loạt". Và đối với các kịch bản lệnh wrapper đơn giản như thế này, dấu nhắc đó gần như vô dụng, vì ngay cả khi bạn chọn "N", nó vẫn chấm dứt perl. – MiffTheFox

+0

Trong Unix, trình bao của bạn phải có một số dạng hàm bí danh mà làm cho nó thậm chí không cần thiết để tạo ra một kịch bản lệnh shell. – jmucchiello

2

tôi không thể tái tạo các hành vi của bạn mô tả:

/* main.c */ 

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    int i; 
    for (i = 0; i < argc; i++) { 
     printf("%s\n", argv[i]); 
    } 
    return 0; 
} 

C:\> ShellCmd.exe a b c 
ShellCmd.exe 
a 
b 
c 

Đó là với Visual Studio 2005.

+0

Hãy thử args trong dấu ngoặc kép như '-e' nói 'hello' '' và lưu ý cách thức chúng bị phân chia. – Schwern

+0

Vâng, nhưng đó là điều bình thường đối với vỏ Windows. Tôi không thấy làm thế nào mà làm cho wrapper của bạn khác nhau từ perl chính nó. – hexten

+0

Trình bao bọc nhận "-e", "nói" xin chào "" trên argv. Các dấu ngoặc kép xung quanh "say" hello "" đã bị lột vỏ. Nếu bạn chỉ cần sau đó vượt qua đó cùng với một chương trình khác nó sẽ nhận được "-e nói" hello "" mà Windows không biết làm thế nào để đối phó với. Các wrapper (nhiều khả năng vỏ) dải các dấu ngoặc kép để chương trình nội bộ không có lợi ích của chúng. Bạn sẽ thấy nó nếu chương trình của bạn đã cố gắng gọi một số khác với argv. – Schwern

0

Windows luôn là trường hợp kỳ lạ. Cá nhân, tôi sẽ không cố gắng mã cho ngoại lệ môi trường Windows. Một số lựa chọn thay thế đang sử dụng trình bao bọc "bat" hoặc ftype/assoc Registry hacks cho phần mở rộng tệp.

Windows bỏ qua dòng shebang khi chạy từ vỏ lệnh DOS, nhưng trớ trêu thay khi sử dụng nó khi CGI-ing Perl trong Apache cho Windows. Tôi đã mệt mỏi khi mã hóa #! C: /perl/bin/perl.exe trực tiếp trong các chương trình web của tôi vì các vấn đề về tính di động khi chuyển sang môi trường * nix. Thay vào đó, tôi tạo một thư mục c: \ usr \ bin trên máy trạm của tôi và sao chép nhị phân perl.exe từ vị trí mặc định của nó, thường là c: \ perl \ bin cho AS Perl và c: \ strawberry \ perl \ bin cho Strawberry Perl. Vì vậy, trong chế độ phát triển web trên Windows, các chương trình của tôi sẽ không bị phá vỡ khi di chuyển đến một máy chủ web Linux/UNIX và tôi có thể sử dụng dòng shebang chuẩn "#!/Usr/bin/perl -w" mà không cần phải đi SED điên trước triển khai. :)

Trong môi trường trình bao lệnh DOS, tôi chỉ hoặc đặt PATH của tôi một cách rõ ràng hoặc tạo một ftype trỏ đến nhị phân perl.exe thực tế với công tắc nhúng -Mperl5i. Dòng shebang bị bỏ qua.

ftype p5i=c:\strawberry\perl\bin\perl.exe -Mperl5i %1 %* 
assoc .pl=p5i 

Sau đó từ dòng lệnh DOS bạn chỉ có thể gọi là "program.pl" của bản thân thay vì "perl -Mperl5i program.pl"

Vì vậy, "nói" tuyên bố làm việc trong 5.10 mà không cần bất kỳ thêm coaxing chỉ bằng cách nhập tên của chính chương trình Perl, và nó sẽ chấp nhận một số biến của các đối số dòng lệnh.

0

Sử dụng CommandLineToArgvW để tạo argv của bạn hoặc chỉ chuyển trực tiếp dòng lệnh của bạn tới CreateProcess.

Của couse, điều này đòi hỏi một giải pháp Windows riêng biệt, nhưng bạn nói rằng bạn không sao, điều này tương đối đơn giản và thường mã hóa các phần quan trọng đặc biệt cho hệ thống đích giúp tích hợp (từ POV của người dùng) đáng kể. YMMV.

Nếu bạn muốn chạy cùng một chương trình cả khi có và không có bảng điều khiển, bạn nên đọc Raymond Chen về chủ đề.

0

Trên Windows, ở cấp hệ thống, dòng lệnh được chuyển đến chương trình được khởi chạy dưới dạng một chuỗi UTF-16 duy nhất, vì vậy bất kỳ dấu ngoặc nhập nào được nhập trong trình bao đều được chuyển thành. Vì vậy, các dấu ngoặc kép từ ví dụ của bạn không bị xóa. Điều này hoàn toàn khác với thế giới POSIX nơi mà trình bao thực hiện phân tích cú pháp và chương trình khởi chạy nhận được một chuỗi các chuỗi.

Tôi đã mô tả ở đây hành vi ở cấp hệ thống.Tuy nhiên, giữa chương trình C (hoặc Perl) của bạn thường có thư viện chuẩn C đang phân tích cú pháp chuỗi dòng lệnh hệ thống để cung cấp cho nó main() hoặc wmain()argv[]. Điều này được thực hiện bên trong quá trình của bạn, nhưng bạn vẫn có thể truy cập chuỗi dòng lệnh gốc với GetCommandLineW() nếu bạn thực sự muốn kiểm soát cách phân tích cú pháp được thực hiện hoặc nhận chuỗi trong mã hóa UTF-16 đầy đủ của nó.

Để tìm hiểu thêm về những khuyết tật dòng lệnh phân tích Windows, đọc phần sau đây:

Bạn cũng có thể quan tâm bởi mã của wrapper I wrote cho Padre trên Win32: đây là một chương trình GUI (có nghĩa là nó sẽ không mở một giao diện điều khiển nếu được khởi chạy từ menu Start) được gọi là padre.exe nhúng perl để khởi chạy padre Kịch bản Perl. Nó cũng thực hiện một mẹo nhỏ: nó thay đổi argv[0] để trỏ nó đến perl.exe để $^X sẽ là một cái gì đó có thể sử dụng để khởi chạy các tập lệnh perl bên ngoài.

execv bạn đang sử dụng trong mã ví dụ của mình chỉ là mô phỏng trong thư viện C của hành vi giống POSIX. Đặc biệt, nó sẽ không thêm dấu ngoặc kép xung quanh các đối số của bạn để perl được khởi chạy hoạt động như mong đợi. Bạn phải tự mình làm điều đó.

Lưu ý rằng do thực tế là khách hàng chịu trách nhiệm phân tích cú pháp, mỗi khách hàng của khách hàng có thể thực hiện theo cách mà họ muốn. Nhiều người cho phép libc làm điều đó, nhưng không phải tất cả. Vì vậy, các quy tắc tạo dòng lệnh chung trên Windows không thể tồn tại: quy tắc phụ thuộc vào chương trình được khởi chạy. Bạn vẫn có thể quan tâm đến việc thực hiện "nỗ lực tốt nhất" như Win32::ShellQuote.

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