Hazme un sándwich

21

XKCD: Sandwich

Desafío: escriba un archivo MAKE, lo que llevaría a este comportamiento:

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

Reglas:

  1. Debería funcionar en una máquina Linux, donde el usuario no es root pero se le permite usar sudo.
  2. No se debe decir Okaya ningún comando make más corto (por ejemplo sudo make sandwich).
  3. El segundo comando debería funcionar debido a sudo, no porque es la segunda invocación.

Pautas:

  1. Sea breve (después de todo, es un sitio de Code Golf).
  2. Sería bueno si realmente hiciera un sándwich.
  3. Intenta esconder inteligentemente por qué sudohace la diferencia.

El ganador se decidirá por votos.

Ugoren
fuente
@ardnew, desafortunadamente, solicité específicamente escribir un archivo MAKE, que, creo, invalida las soluciones basadas en parches make.
ugoren
totalmente de acuerdo, @ugoren. no significaba que ese comentario descartara el desafío o sugiriera una solución
nuevo

Respuestas:

12

Está bien, voy a morder. Esto no necesariamente se adhiere a la directriz # 3, pero hace un trabajo justo en las otras dos pautas. También se limpia después de sí mismo, como debería hacerlo cualquier buen sándwich.

.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

(Menos con errores, y con suerte un poco menos aburrido, que mi presentación inicial).

caja de pan
fuente
Parece que viola la regla # 2 - sudo make me sandwich.
ugoren
&& test -e ./a
luser droog
Argh, tienes razón. Esta versión debería hacer un mejor trabajo al observar las reglas.
breadbox
1
ciertamente tienes el nombre más apropiado, @breadbox
ardnew
9

Una solución bastante compacta que ignora la directriz # 2 (127 caracteres, incluyendo algunos espacios en blanco innecesarios). Sigo la práctica de breadbox de limpiar después de mí mismo. ¡No coloque ningún otro archivo en el mismo directorio que el archivo MAKE! Además, tenga en cuenta que se debe llamar al archivo MAKE Makefile, otros nombres no funcionarán.

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

Uso:

$ 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

Me gusta la forma en que este trata con la directriz # 3. Solo una pulsación de Shifthace la diferencia.

Gilles 'SO- deja de ser malvado'
fuente
3

Esta solución no se adhiere a la directriz n. ° 2, ¿o contar vagamente en forma de sándwich? Comencé con una especie de tema de palíndromo al principio, pero solo pude encontrar tantas formas de hacer que las líneas sean simétricas sin recurrir a cojo real code # ecod laer. No tomé muy en serio la directriz # 1, la estética es lo primero.

Recuerda que es un archivo MAKE; las 3 líneas sucesivas que comienzan con if, rmy echocomienzan con una pestaña. Las otras líneas sangradas comienzan con espacios.

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

Uso (los comandos se pueden emitir en cualquier orden):

$ 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

En cuanto a la directriz # 3, esto no está inteligentemente oculto, solo un poco extraño. Algunos consejos:

Hay dos pruebas diferentes: una búsqueda de SUDO_USER, y una prueba de si id -ulas impresiones 0. ve usted por qué What?se no impresa de la raíz? ¿Ves cómo la falta de SUDO_USERcausas Okayno se imprime?

Gilles 'SO- deja de ser malvado'
fuente
2

Aquí hay un primer paso usando una técnica diferente y más 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

Estoy bastante seguro de que hay más que puedo hacer con esto: hacer que responda a otros comandos de entrada, por ejemplo. Tendré que trabajar en la ofuscación del interruptor raíz y en la preparación del sándwich real.

Benedicto
fuente