Wyzwanie : napisz pojedynczy plik skryptu, foo.cmd
który można wywołać z waniliowego cmd.exe
monitu Windows (nie PowerShell, nie w trybie administratora), aby wykonać dowolny kod specyficzny dla Windows ...
> .\foo.cmd
Hello Windows!
... ale również powoływać niezmienione od typowego POSIX (Linux / OSX) shell prompt ( bash
, tcsh
lub zsh
), aby wykonać dowolny POSIX-specyficzny kod:
$ chmod a+x foo.cmd
$ ./foo.cmd
Hello POSIX!
... bez konieczności instalowania lub tworzenia zewnętrznych tłumaczy / narzędzi.
Wiem, że jest to możliwe, ale w przypadku cruft (tj. W systemie Windows jedna lub dwie linie śmieci / komunikat o błędzie są drukowane na stderr lub stdout przed „Hello Windows!”).
Kryterium wygranej jest minimalizacja (pierwszej) liczby linii cruft i (drugiej) liczby znaków cruft.
Cruft można zdefiniować jako dowolne wyjście konsoli (standardowe lub standardowe), które nie jest generowane przez (dowolny) kod ładunku. Puste linie są liczone w liczbie wierszy. Nowe linie nie są liczone w liczbie znaków. Wyniki Cruft należy zsumować na obu platformach. Nie bierzmy pod uwagę takich mechanizmów, cls
które wymiatają cruft, ale kosztem wyczyszczenia również poprzedniego wyjścia terminala. Jeśli system Windows powtórzy polecenia, ponieważ jeszcze tego nie zrobiłeś @echo off
, wykluczmy znaki, które spędza na drukowaniu bieżącego katalogu i monit.
Drugim kryterium jest prostota / elegancja zastosowanego rozwiązania foo.cmd
: jeśli „infrastruktura” jest zdefiniowana jako dowolny znak nieobjęty bezpośrednio dowolnym kodem ładunku, to najpierw należy zminimalizować liczbę wierszy zawierających znaki infrastruktury, a następnie całkowitą liczbę infrastruktury postacie.
Dodatkowe wyróżnienia, jeśli część POSIX będzie działać pomimo tego, że plik ma zakończenia linii CRLF! (Nie jestem pewien, czy ostatnia część jest nawet możliwa.)
Moje istniejące rozwiązanie, które opublikuję tutaj, gdy inni będą mieli okazję, wykorzystuje 6 linii kodu infrastruktury (52 znaki z wyłączeniem nowych linii). Tworzy 5 wierszy cruft, z których dwa są puste, z których wszystkie występują w systemie Windows (30 znaków z wyłączeniem nowych wierszy i wykluczenia bieżącego ciągu katalogu / zachęty, który pojawia się w dwóch z tych wierszy).
Odpowiedzi:
0 linii cruft, 0 znaków cruft, 2 infra. linie, 21 infra. znaki, CRLF ok
Usunięto inne rozwiązanie.
17 znaków korzystających
exit /b
z odpowiedzi Digital Trauma:źródło
: command not found
gdy pusta linia wkradła się do ładunku posix, ale w końcu zorientowałem się, że nie chodzi:
o pierwszą linię, ale raczej z powodu braku ochrony CRLF#
. To była dla mnie wiadomość, że#!
linia nie jest potrzebna - która była odpowiedzialna za dwie linie Windows Cruft w mojej poprzedniej wersji.: ` >&3` \
do każdej linii ładunku, myślę, że można powiedzieć, że jej koszt infrastruktury jest arbitralnie wysoki.#
konieczny?Zdobądź 0 cruft + 4 infra linie + 32 infra znaki. LF i CRLF OK.
Jest to oparte na tym, co znalazłem na tym blogu , z usuniętymi bitami Amigi i innymi niepotrzebnymi liniami. Ukryłem wiersze DOS w komentarzach zamiast używać
\
kontynuacji wiersza, aby działało to zarówno z CRLF, jak i LF.Z końcówkami linii DOS CRLF lub * nix LF, działa na Ubuntu, OSX i wine:
Aby utworzyć to dokładnie (z CRLF) na maszynie * nix (w tym OSX), wklej następujące elementy do terminala:
źródło
dosix
to też miłe imię. Ale na moim Macu (OS 10.9.4, jądro Darwina w wersji 13.3.0, GNU bash w wersji 3.2.51) nie działa z:./dosix.cmd: line 13: syntax error: unexpected end of file
Wiesz, dlaczego?Już opublikuję rozwiązanie, którego używałem, ponieważ zostało już pobite. Dzięki uprzejmości mojego kolegi, który moim zdaniem musiał przeczytać ten sam wpis na blogu, co Digital Trauma .
#!
nie jest zainteresowany (więc w przypadku standardowych tłumaczy, takich jaksh
i przyjaciele, nie działa)źródło
#!
, co oznacza, że twoja jedyna jak dotąd odpowiedź jest poprawnym skryptem w systemie POSIX. Pewnie niektóre z pozostałych mogą działać, jeśli - ale tylko wtedy, gdy są uruchamiane z powłoki z obejściem wadliwych skryptów.#!
linii, ale będą używać różnych powłok do interpretacji skryptu. Oznacza to, że „skrypt”, który się nie zaczyna,#!
musi być poprawny nie tylko w jednej powłoce, ale w każdej powłoce, którą mógłby być interpretowany. Co gorsza, działa tylko wtedy, gdy jest uruchamiany z innej powłoki. Taki skrypt może działać z poziomu wiersza poleceń, ale nie w kontekście, w którym ostatecznie zamierzasz go używać.#!
wiersz w mojej edytowanej odpowiedzi (1 linia infrastruktury z 21 znakami) może być połączony z odpowiedzią innej osoby przy koszcie tylko dwóch wierszy (z których jeden jest pusty) lub 23 znaki.Podsumowanie / synteza odpowiedzi i dyskusja
To była świetna zabawa i wiele się nauczyłem.
Niektóre crufty specyficzne dla systemu Windows są nieuniknione, jeśli w systemie POSIX konieczne jest uruchomienie skryptu za pomocą
#!
wiersza. Jeśli nie masz innego wyjścia, jak to zrobić, to ten wiersz:jest prawdopodobnie najlepszym, co może dostać. Powoduje to, że jedna konsola Windows wyświetla jeden pusty wiersz i jeden wiersz cruft. Jednakże, może być w stanie uciec bez
#!
linii: na większości systemów, jeden z typowych tłumaczy powłoki zakończy się wykonywanie skryptu (problem jest to, że nie jest powszechnie przewidywalne który interpreter, że będzie - to zależy, ale będzie niekoniecznie musi być identyczny z powłoką używaną do wywołania polecenia).Poza tą trudną pierwszą linią pojawiły się naprawdę genialne rozwiązania bezkrwiste. Zwycięskie zgłoszenie autorstwa jimmy23013 składało się tylko z dwóch krótkich linii infrastruktury i wykorzystało podwójną rolę
:
postaci do wprowadzenia „cichej” linii na obu platformach (jako de facto nieobecnośćsh
i znajomi oraz jako etykieta znacznik wcmd.exe
):Możliwe jest uruchomienie takiego skryptu w systemach POSIX, nawet pomimo zakończenia linii CRLF, ale aby to zrobić dla większości interpreterów, musisz zakończyć każdy wiersz sekcji POSIX (nawet puste wiersze) znakiem komentarza lub komentarza.
Wreszcie, oto dwa warianty rozwiązania, które opracowałem w oparciu o wkład wszystkich. Mogą być prawie najlepsze ze wszystkich światów, ponieważ minimalizują szkody wynikające z braku
#!
i sprawiają, że kompatybilność z CRLF jest jeszcze bardziej płynna. Potrzebne są dwie dodatkowe linie infrastruktury. Tylko jedna (znormalizowana) linia musi być interpretowana przez nieprzewidywalną powłokę POSIX, a ta linia pozwala wybrać powłokę dla reszty skryptu (bash
w poniższym przykładzie):Zaletą tych rozwiązań heredoc jest to, że wciąż są one odporne na CRLF: tak długo, jak będzie
<<:Z
na końcu linii, procesor heredoc będzie faktycznie szukał i znajdzie token:Z\r
Na koniec możesz pozbyć się tych irytujących komentarzy na końcu linii i nadal zachować odporność na CRLF, usuwając
\r
znaki przed przekazaniem linii do powłoki. Powoduje to nieco większą wiarę w nieprzewidywalną powłokę (byłoby miło użyć{ tr -d \\r|bash;}
zamiast tego,(tr -d \\r|bash)
ale nawiasy klamrowe to tylko składnia bash):Oczywiście takie podejście poświęca zdolność do przesyłania danych wejściowych standardowego wejścia do skryptu.
źródło