Mach mir ein Sandwich

21

XKCD: Sandwich

Herausforderung: Schreiben Sie ein Makefile, das zu folgendem Verhalten führen würde:

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

Regeln:

  1. Sollte auf einem Linux-Computer funktionieren, auf dem der Benutzer nicht root ist, sondern verwenden darf sudo.
  2. Darf Okayzu keinem kürzeren make-Befehl sagen (zB sudo make sandwich).
  3. Der zweite Befehl sollte wegen funktionieren sudo , nicht weil es der zweite Aufruf ist.

Richtlinien:

  1. Fassen Sie sich kurz (schließlich handelt es sich um eine Code Golf-Site).
  2. Es wäre schön, wenn es tatsächlich ein Sandwich machen würde.
  3. Versuchen Sie klug zu verbergen, warum sudodas einen Unterschied macht.

Der Gewinner wird per Abstimmung ermittelt.

ugoren
quelle
@ardnew, leider habe ich ausdrücklich darum gebeten, ein Makefile zu schreiben, das meiner Meinung nach Lösungen, die auf dem Patchen basieren, ungültig macht make.
Ugoren
stimme vollkommen zu, @ugoren. bedeutete nicht, dass dieser Kommentar die Herausforderung
ablehnte

Antworten:

12

Okay, ich werde beißen. Dies entspricht nicht unbedingt der Richtlinie Nr. 3, leistet jedoch bei den anderen beiden Richtlinien gute Arbeit. Es räumt auch nach sich selbst auf, wie es jeder gute Sandwichmacher sollte.

.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

(Weniger fehlerhaft und hoffentlich ein bisschen weniger langweilig als meine ursprüngliche Vorlage.)

Brot-Box
quelle
Sieht aus wie es Regel # 2 verletzt - sudo make me sandwich.
Ugoren
&& test -e ./a
Luser Droog
Argh, du hast recht. Diese Version sollte die Regeln besser einhalten.
Brotkasten
1
Sie haben sicherlich den am besten geeigneten Namen, @breadbox
Ardnew
9

Eine relativ kompakte Lösung, die die Richtlinie 2 ignoriert (127 Zeichen, einschließlich unnötiger Leerzeichen). Ich folge der Praxis von breadbox, nach mir selbst aufzuräumen. Legen Sie keine andere Datei in dasselbe Verzeichnis wie das Makefile! Beachten Sie auch, dass das Makefile aufgerufen werden muss Makefile, andere Namen funktionieren nicht.

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

Verwendung:

$ 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

Ich mag die Art und Weise, wie diese mit Leitlinie Nr. 3 umgeht. Nur ein Druck auf Shiftmacht den Unterschied.

Gilles 'SO - hör auf böse zu sein'
quelle
3

Diese Lösung entspricht nicht der Richtlinie Nr. 2 - oder zählt eine vage Sandwichform? Anfangs ging ich auf eine Art Palindrom-Thema ein, aber ich fand nur so viele Möglichkeiten, Linien symmetrisch zu machen, ohne auf Lahmheit zurückzugreifen real code # ecod laer. Ich habe Leitlinie Nr. 1 nicht sehr ernst genommen, da steht die Ästhetik an erster Stelle.

Denken Sie daran, dass es sich um ein Makefile handelt. Die 3 aufeinanderfolgenden Zeilen beginnend mit if, rmund echomit einer Lasche beginnen. Die anderen eingerückten Zeilen beginnen mit Leerzeichen.

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

Verwendung (die Befehle können in beliebiger Reihenfolge ausgegeben werden):

$ 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

Was Leitlinie Nr. 3 betrifft, so ist dies nicht geschickt versteckt, sondern nur ein wenig seltsam. Einige Hinweise:

Es gibt zwei verschiedene Tests: eine Suche nach SUDO_USERund eine Prüfung, ob der id -uWert 0 ausgegeben wird. Sehen Sie, warum der What?Wert nicht für root ausgegeben wird? Sehen Sie, wie der Mangel an SUDO_USERUrsachen Okaynicht gedruckt werden kann?

Gilles 'SO - hör auf böse zu sein'
quelle
2

Hier ist ein erster Versuch mit einer anderen und einfacheren Technik:

.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

Ich bin mir ziemlich sicher, dass ich damit mehr anfangen kann - zum Beispiel, um auf andere Eingabebefehle zu reagieren. Ich muss an der Root-Switch-Verschleierung und der eigentlichen Sandwich-Herstellung arbeiten.

Benedikt
quelle