Fais moi un sandwich

21

XKCD: Sandwich

Défi: Écrivez un makefile, ce qui conduirait à ce comportement:

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

Règles:

  1. Devrait fonctionner sur une machine Linux, où l'utilisateur n'est pas root mais autorisé à l'utiliser sudo.
  2. Ne doit pas dire Okayà une commande make plus courte (par exemple sudo make sandwich).
  3. La deuxième commande devrait fonctionner à cause de sudo, pas parce que c'est la deuxième invocation.

Des lignes directrices:

  1. Soyez bref (après tout, c'est un site Code Golf).
  2. Ce serait bien si cela faisait un sandwich.
  3. Essayez de cacher intelligemment pourquoi cela sudofait une différence.

Le gagnant sera décidé par vote.

ugoren
la source
@ardnew, malheureusement, j'ai spécifiquement demandé d'écrire un makefile, ce qui, je pense, invalide les solutions basées sur les correctifs make.
ugoren
tout à fait d'accord, @ugoren. ne voulait pas que ce commentaire rejette le défi ou suggère une solution
ardnew

Réponses:

12

D'accord, je vais mordre. Cela n'adhère pas nécessairement à la directive n ° 3, mais il fait un travail équitable sur les deux autres directives. Il nettoie également après lui-même, comme tout bon fabricant de sandwich devrait le faire.

.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

(Moins buggy, et j'espère un peu moins ennuyeux, que ma soumission initiale.)

boite à pain
la source
On dirait que cela viole la règle # 2 - sudo make me sandwich.
ugoren
&& test -e ./a
luser droog
Argh, tu as raison. Cette version devrait mieux respecter les règles.
boîte à pain du
1
vous avez certainement le nom le plus approprié, @breadbox
ardnew
9

Une solution assez compacte qui ignore la directive # 2 (127 caractères, y compris des espaces inutiles). Je suis la pratique de la boîte à pain de nettoyer après moi-même. Ne placez aucun autre fichier dans le même répertoire que le makefile! Notez également que le makefile doit être appelé Makefile, les autres noms ne fonctionneront pas.

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

Usage:

$ 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

J'aime la façon dont celle-ci traite de la directive n ° 3. Une simple pression sur Shiftfait la différence.

Gilles 'SO- arrête d'être méchant'
la source
3

Cette solution n'adhère pas à la directive n ° 2 - ou est-ce que la forme vaguement en sandwich compte? J'ai commencé sur une sorte de thème palindrome au début, mais je ne pouvais trouver que de nombreuses façons de rendre les lignes symétriques sans avoir recours à des boiteux real code # ecod laer. Je n'ai pas pris la directive n ° 1 très au sérieux, l'esthétique passe avant tout.

N'oubliez pas que c'est un makefile; les 3 lignes successives commençant par if, rmet echocommencent par une tabulation. Les autres lignes en retrait commencent par des espaces.

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

Utilisation (les commandes peuvent être émises dans n'importe quel ordre):

$ 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

Quant à la directive n ° 3, elle n'est pas astucieusement cachée, juste un peu bizarrement. Quelques conseils:

Il existe deux tests différents: un recherche SUDO_USERet un test pour savoir si id -uimprime 0. Voyez-vous pourquoi What?n'est pas imprimé pour root? Voyez-vous comment le manque de SUDO_USERcauses Okayne s'imprime pas?

Gilles 'SO- arrête d'être méchant'
la source
2

Voici un premier essai en utilisant une technique différente et plus simple:

.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

Je suis presque sûr qu'il y a plus que je peux faire avec cela - faites-le répondre à d'autres commandes d'entrée par exemple. Je vais devoir travailler sur l'obfuscation du commutateur racine et la fabrication du sandwich.

Benoît
la source