Сделай мне бутерброд

21

XKCD: сэндвич

Задача: Напишите make-файл, который приведет к такому поведению:

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

Правила:

  1. Должен работать на компьютере с Linux, где пользователь не является пользователем root, но ему разрешено использовать sudo.
  2. Не должен говорить Okayкакой-либо более короткой команде make (например sudo make sandwich).
  3. Вторая команда должна работать из-за sudo, а не потому, что это второй вызов.

Методические рекомендации:

  1. Будьте кратки (в конце концов, это сайт Code Golf).
  2. Было бы неплохо, если бы он действительно сделал бутерброд.
  3. Попробуйте хитро спрятать, почему sudoимеет значение.

Победитель будет определен голосованием.

ugoren
источник
@ardnew, к сожалению, я специально попросил написать make-файл, который, я думаю, лишает законной силы решения, основанные на исправлениях make.
Угорен
полностью согласен, @ugoren. не означало, что этот комментарий отклонит вызов или предложит решение
ardnew

Ответы:

12

Хорошо, я укушу Это не обязательно соответствует руководству № 3, но оно справляется с двумя другими рекомендациями. Это также убирает после себя, как должен любой хороший производитель сэндвича.

.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

(Менее глючный, и, надеюсь, немного менее скучный, чем мое первоначальное представление.)

Хлебница
источник
Похоже, это нарушает правило № 2 - sudo make me sandwich.
Угорен
&& test -e ./a
Люзер Дрог
Ааа, ты прав. Эта версия должна лучше выполнять правила.
хлебница
1
у вас наверняка есть самое подходящее имя, @breadbox
ardnew
9

Довольно компактное решение, которое игнорирует рекомендацию № 2 (127 символов, включая некоторые ненужные пробелы). Я следую практике уборки после себя. Не помещайте другие файлы в тот же каталог, что и make-файл! Также обратите внимание, что make-файл должен быть вызван Makefile, другие имена не будут работать.

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

Использование:

$ 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

Мне нравится, как этот справляется с рекомендацией № 3. Только одно нажатие Shiftимеет значение.

Жиль "ТАК - перестать быть злым
источник
3

Это решение не соответствует руководству № 2 - или имеет неопределенный подсчет в форме сэндвича? Вначале я остановился на некой палиндромной теме, но я мог найти только много способов сделать симметрию линий, не прибегая к хромоте real code # ecod laer. Я не относился к руководству № 1 очень серьезно, эстетика на первом месте.

Помните, что это make-файл; в 3 последовательных строк , начинающихся с if, rmи echoначать с язычком. Другие отступы начинаются с пробелов.

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

Использование (команды могут быть введены в любом порядке):

$ 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

Что касается руководящего принципа № 3, это не скрыто, просто немного странно. Некоторые намеки:

Есть два различных тестов: один поиск SUDO_USER, и один тест ли id -uгравюр 0. Видите ли вы , почему What?это не печатаются на корень? Вы видите, как отсутствие SUDO_USERпричин Okayне печатать?

Жиль "ТАК - перестать быть злым
источник
2

Вот первый шаг с использованием другой и более простой техники:

.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

Я почти уверен, что с этим можно многое сделать - например, заставить его реагировать на другие команды ввода. Мне придется поработать над обфускацией корневого переключателя и фактическим приготовлением бутерброда.

Бенедикт
источник