Zrób mi kanapkę

21

XKCD: Kanapka

Wyzwanie: Napisz plik makefile, który doprowadziłby do takiego zachowania:

% make me a sandwich
What? Make it yourself
% sudo make me a sandwich
Okay

Zasady:

  1. Powinien działać na komputerze z systemem Linux, na którym użytkownik nie jest rootem, ale może go używać sudo.
  2. Nie wolno mówić Okayżadnemu krótszemu poleceniu make (np sudo make sandwich.).
  3. Drugie polecenie powinno działać z powodu sudo, a nie dlatego, że jest to drugie wywołanie.

Wytyczne:

  1. Krótko mówiąc (w końcu jest to strona Code Golf).
  2. Byłoby miło, gdyby rzeczywiście zrobił kanapkę.
  3. Spróbuj sprytnie ukryć, dlaczego to sudorobi różnicę.

Zwycięzca zostanie wyłoniony w drodze głosowania.

ugoren
źródło
@ardnew, niestety, specjalnie poprosiłem o napisanie makefile, który moim zdaniem unieważnia rozwiązania oparte na łataniu make.
ugoren
całkowicie się zgadzam, @ugoren. nie oznaczało, że ten komentarz odrzuca wyzwanie lub sugeruje rozwiązanie
nowy

Odpowiedzi:

12

Dobra, ugryzę. Niekoniecznie musi to być zgodne z wytyczną nr 3, ale dobrze spełnia pozostałe dwie wytyczne. Oczyszcza się także po sobie, jak powinien każdy dobry producent kanapek.

.SILENT:

%:%.c
        $(CC) -o $@ $^ && rm -f $^

default:
        echo 'The makings for a sandwich are here.'

a.c:
        echo '#include <stdio.h>' > a.c
        echo 'int main() {' >> a.c
        echo '  char *txt[] = { "What? Make it yourself.", "Okay." };' >> a.c
        echo '  int n = 0;' >> a.c
        echo '  while (getchar() != EOF) n ^= 1;' >> a.c
        echo '  puts(txt[n]); return 0; }' >> a.c

me.c:
        echo '#include <stdio.h>' > me.c
        echo '#include <unistd.h>' >> me.c
        echo 'int main() {' >> me.c
        echo '  char *txt[] = { "/dev/null", "sandwich" };' >> me.c
        echo '  puts(txt[!getuid()]); return 0; }' >> me.c

sandwich:
        ./me | ./a | tee `./me`
        rm -f me a

clean:
        rm -f sandwich

(Mniej buggy i mam nadzieję, że nieco mniej nudne, niż moje początkowe zgłoszenie.)

chlebak
źródło
Wygląda na to, że narusza zasadę nr 2 - sudo make me sandwich.
ugoren
&& test -e ./a
luser droog
Argh, masz rację. Ta wersja powinna lepiej wykonywać zasady.
breadbox
1
z pewnością masz najbardziej odpowiednią nazwę, @breadbox
ardnew
9

Dość kompaktowe rozwiązanie, które ignoruje wytyczną nr 2 (127 znaków, w tym niektóre niepotrzebne białe znaki). Śledzę praktyki Breadbox jest o sprzątanie po sobie. Nie umieszczaj żadnych innych plików w tym samym katalogu, co plik makefile! Zauważ też, że plik makefile musi zostać wywołany Makefile, inne nazwy nie będą działać.

me: ; echo echo Okay >$@
a: ; chmod u=x me
sandwich: ; ./me 2>/dev/null || echo 'What? Make it yourself'; rm -f [!M]*
.SILENT:

Stosowanie:

$ make me a sandwich
What? Make it yourself
$ sudo make me a sandwich
Okay
$ sudo make me sandwich  
What? Make it yourself
$ sudo make a sandwich
chmod: cannot access `me': No such file or directory
make: *** [a] Error 1
$ sudo make sandwich  
What? Make it yourself

Podoba mi się sposób, w jaki ten radzi sobie z wytyczną nr 3. Tylko jedno naciśnięcie Shiftrobi różnicę.

Gilles „SO- przestań być zły”
źródło
3

To rozwiązanie nie jest zgodne z wytyczną nr 2 - czy liczy się nieokreślony kształt kanapki? Na początku zajmowałem się rodzajem palindromu, ale mogłem znaleźć tylko tyle sposobów, aby linie były symetryczne bez uciekania się do kulawizny real code # ecod laer. Wytycznej nr 1 nie potraktowałem poważnie, estetyka jest na pierwszym miejscu.

Pamiętaj, że jest to plik makefile; na 3 kolejne linie począwszy if, rma echozaczynają się zakładki. Inne wcięte linie zaczynają się od spacji.

me : mr ; env | grep -q DO_US || rm -- mr || SU_OD q- perg | vne ; rm : em
                            .SILENT:##:TNELIS.
                              . = a.  .a = .
$(.:.=):;:>$@
sandwich:
    if expr>/dev/null $$(id -u); then echo 'What? Make it yourself'; fi
    rm f- a me mr 2>/dev/null
    echo Okay
mr : ; true : ; touch me : em f- mr || rm -f me : em hcuot ; : eurt ; : rm

Sposób użycia (polecenia mogą być wydawane w dowolnej kolejności):

$ sudo make me a sandwich     
Okay
$ sudo make me sandwich  
make: *** [sandwich] Error 1
$ sudo make a sandwich 
make: *** [sandwich] Error 1
$ sudo make sandwich  
make: *** [sandwich] Error 1
$ make me a sandwich
What? Make it yourself
make: *** [sandwich] Error 1

Jeśli chodzi o wytyczną nr 3, nie jest to sprytnie ukryte, tylko nieco dziwnie. Kilka wskazówek:

Istnieją dwa różne testy: jedno wyszukiwanie SUDO_USERi jedno sprawdzenie, czy id -udrukuje 0. Czy widzisz, dlaczego nieWhat? jest drukowany dla roota? Czy widzisz, jak brak przyczyn nie jest drukowany?SUDO_USEROkay

Gilles „SO- przestań być zły”
źródło
2

Oto pierwsze użycie innej i prostszej techniki:

.SILENT:

reset_command:
    @rm -f command

me a sandwich: reset_command
    @echo $@ >> command
    -@make `cat command | tr "\n" "_"` 2>/dev/null

me_a_sandwich_: reset_command
    @if [ `whoami` == "root" ]; then echo "Okay"; else echo "What? Make it yourself."; fi

Jestem prawie pewien, że mogę coś więcej z tym zrobić - na przykład odpowiedzieć na inne polecenia wejściowe. Będę musiał popracować nad zaciemnieniem przełącznika głównego i faktycznym przygotowaniem kanapki.

Benedykt
źródło