2009-07-07 4 views
11

Piszę moduł perl o nazwie perl5i. Jego celem jest ustalenie pokosu wspólnych problemów Perla w jednym module (przy użyciu wielu innych modułów).Pisanie przenośnej linii poleceń w C

Aby wywołać go w linii komend dla jednej linijki, którą napiszesz: perl -Mperl5i -e 'say "Hello"' Myślę, że to zbyt rozwlekłe, więc chciałbym dostarczyć opakowanie perl5i, abyś mógł napisać perl5i -e 'say "Hello"'. Chciałbym również, aby ludzie mogli pisać skrypty z #!/usr/bin/perl5i, więc musi to być skompilowany program C.

Doszedłem do wniosku, że wystarczy nacisnąć "-Mperl5i" na przedniej stronie listy argumentów i wywołać perl. I tego właśnie próbowałem.

#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); 
} 

System Windows komplikuje to podejście. Wygląda na to, że programy w systemie Windows nie przekazują tablicy argumentów, przekazują wszystkie argumenty jako pojedynczy ciąg, a następnie same przetwarzają! Zatem coś takiego jak perl5i -e "say 'Hello'" staje się perl -Mperl5i -e say 'Hello', a Windows nie może sobie poradzić z brakiem cytowania.

Jak mogę sobie z tym poradzić? Zawij wszystko w cudzysłowy i ucieczki w systemie Windows? Czy istnieje biblioteka do obsługi tego dla mnie? Czy istnieje lepsze podejście? Czy mogę po prostu nie generować programu C w systemie Windows i zapisać go jako opakowanie perl, ponieważ nie obsługuje #! tak czy inaczej?

AKTUALIZACJA: Dokładniej, jest to dostarczane oprogramowanie, więc rozwiązania wymagające użycia określonej powłoki lub zmiany konfiguracji powłoki (na przykład alias perl5i='perl -Mperl5i') nie są zadowalające.

Odpowiedz

3

przypadku systemu Windows, należy użyć pliku wsadowego.

perl5i.bat

@echo off 
perl -Mperl5i %* 

%* to wszystkie parametry wiersza polecenia minus %0.

W systemach Unixy wystarczy podobny skrypt powłoki.

Aktualizacja:

myślę, że to będzie działać, ale nie jestem czarodziejem shell i nie masz pod ręką * nix systemu do testowania.

perl5i

#!bash 

perl -Mperl5i [email protected] 

Update:

DUH! Teraz dobrze zrozumiałem Twój komentarz #!. Mój skrypt powłoki działa z poziomu interfejsu CLI, ale nie w linii #!, ponieważ od #!foo zależy, czy plik foo jest plikiem binarnym.

Zignoruj ​​poprzednią aktualizację.

Wygląda na to, że Windows wszystko komplikuje. Myślę, że najlepiej jest użyć pliku wsadowego.

Użytkownik mógł use a file association, kojarzyć .p5i z perl -Mperl5i %*. Oczywiście oznacza to mucking about w rejestrze, który najlepiej unikać IMO. Lepiej dołączyć instrukcje ręcznego dodawania powiązania w dokumentach.

Kolejna zmiana

Czasami warto spojrzeć na to, jak parl robi.

+1

Dzięki, mogę po prostu punt i użyć pliku wsadowego dla systemu Windows. Skrypty powłoki nie wystarczą dla Uniksa, ponieważ #! będzie honorować skompilowane programy. – Schwern

+3

Jednak jedna wada w stosunku do plików wsadowych w systemie Windows - skasowanie skryptu wsadowego spowoduje zgłoszenie "Terminate Batch Process". I dla prostych skryptów tego typu, ta podpowiedź jest prawie bezużyteczna, ponieważ nawet jeśli wybierzesz "N", to nadal będzie ona kończyła się perl. – MiffTheFox

+0

W systemie Unix powłoka powinna mieć jakąś funkcję aliasu, która sprawia, że ​​tworzenie skryptu powłoki jest nawet niepotrzebne. – jmucchiello

2

Nie mogę odtworzyć zachowaniu opisywać:

/* 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 

to z Visual Studio 2005.

+0

Spróbuj argumentować w cudzysłowie, np. "-e", powiedz "cześć" "i zanotuj, jak się rozdzielają. – Schwern

+0

Tak, ale to normalne dla powłoki systemu Windows. Nie widzę, jak to sprawia, że ​​twoje opakowanie różni się od samego perla. – hexten

+0

Opakowanie otrzymuje "-e", "powiedz" cześć "" w argv. Cytaty dotyczące "powiedz" cześć "zostały usunięte przez powłokę. Jeśli po prostu przekażesz to innemu programowi, otrzymasz polecenie "-e say 'hello", którego system Windows nie wie, jak sobie poradzić. Opakowanie (bardziej prawdopodobne, że powłoka) usuwa cytaty, więc program wewnętrzny nie ma z nich korzyści. Zobaczysz, jeśli twój program próbował wywołać inny z argv. – Schwern

0

Windows jest zawsze dziwny przypadek. Osobiście nie próbowałbym kodować dla wyjątków środowiska Windows. Niektóre alternatywy używają "pakowania nietoperzy" lub hacków Ftype/assoc Registry dla rozszerzenia pliku. gdy uruchomiony z linii poleceń DOS

Okna ignoruje linię shebang, ale ironicznie używa go podczas CGI-ing Perl w Apache dla Windows. Mam już dość kodowania #! C: /perl/bin/perl.exe bezpośrednio w moich programach internetowych z powodu problemów z przenośnością podczas przechodzenia do środowiska * nix. Zamiast tego utworzyłem katalog c: \ usr \ bin na mojej stacji roboczej i skopiowałem plik binarny perl.exe z domyślnej lokalizacji, zwykle c: \ perl \ bin dla AS Perl i c: \ strawberry \ perl \ bin dla Strawberry Perl. Tak więc w trybie programowania w systemie Windows moje programy nie uległyby awarii po migracji do hosta Linux/UNIX i mogłem użyć standardowego numeru linii Shebang "#!/Usr/bin/perl -w" bez konieczności wcześniejszego przejścia do SED do wdrożenia. :)

W środowisku powłoki poleceń DOS ustawiam jawnie ścieżkę PATH lub utworzę typ ftype wskazujący na rzeczywistą wersję binarną perl.exe z osadzonym przełącznikiem -Mperl5i. Linia shebang jest ignorowana.

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

Następnie z wiersza poleceń DOS można po prostu nazwać „program.pl” sam zamiast „Perl -Mperl5i program.pl”

więc „powiedzieć” oświadczenie pracował w 5.10 bez dodatkowego namawiając się po prostu wprowadzając nazwę samego programu Perla, a także akceptował zmienną liczbę argumentów linii poleceń.

0

Użyj CommandLineToArgvW do zbudowania argv lub po prostu przekaż linię poleceń bezpośrednio do CreateProcess.

Co ważne, wymaga to osobnego rozwiązania specyficznego dla systemu Windows, ale powiedziałeś, że wszystko w porządku, jest to stosunkowo proste, a często kodowanie kluczowych elementów w systemie docelowym pomaga w integracji (z POV użytkowników) znacząco. YMMV.

Jeśli chcesz uruchomić ten sam program, jak i bez konsoli, należy zapoznać Raymond Chen na ten temat.

0

W systemie Windows na poziomie systemowym, wiersza polecenia jest przekazywane do uruchomionego programu jako pojedynczy ciąg znaków UTF-16, więc wszelkie cytaty weszły w powłoce są przekazywane jak jest. Tak więc podwójne cytaty z twojego przykładu nie są usuwane. Różni się to od świata POSIX, w którym powłoka wykonuje zadanie parsowania, a uruchomiony program otrzymuje tablicę ciągów.

Opisałem tutaj zachowanie na poziomie systemowym.Jednak między twoim programem C (lub twoim Perlem) zwykle znajduje się biblioteka standardowa C, która analizuje ciąg wiersza poleceń systemu, aby przekazać go do main() lub wmain() jako argv[]. Odbywa się to w twoim procesie, ale nadal możesz uzyskać dostęp do oryginalnego łańcucha wiersza poleceń przy pomocy GetCommandLineW(), jeśli naprawdę chcesz kontrolować, jak parsowanie jest wykonywane, lub pobierz ciąg w pełnym kodowaniu UTF-16.

Aby dowiedzieć się więcej na temat dziwactw wiersza polecenia parsowania Windows przeczytać:

Możesz być także zainteresowany o kodzie wrapper I wrote dla Padre na Win32: jest to program GUI (co oznacza, że ​​nie otworzy konsoli po uruchomieniu z menu Start) o nazwie padre.exe, który osadza perla w celu uruchomienia padre Skrypt Perla. Wykonuje również małą sztuczkę: zmienia się argv[0], aby wskazać ją na perl.exe, dzięki czemu $^X będzie czymś użytecznym do uruchomienia zewnętrznych skryptów perl.

Użyty w przykładowym kodzie execv jest po prostu emulacją w bibliotece C zachowania podobnego do POSIX. W szczególności nie doda kwotowań wokół twoich argumentów, tak aby uruchamiany perl działał zgodnie z oczekiwaniami. Musisz to zrobić sam.

Należy pamiętać, że ze względu na to, że klient jest odpowiedzialny za przetwarzanie, każdy klient kliencki może zrobić to, co chce. Wiele pozwól libc to zrobić, ale nie wszystkie. Tak więc ogólne reguły generowania wiersza polecenia w systemie Windows nie mogą istnieć: reguła zależy od uruchomionego programu. Możesz nadal być zainteresowany implementacją typu "best effort", taką jak Win32::ShellQuote.