Buatkan saya sandwich

21

XKCD: Sandwich

Tantangan: Tulis makefile, yang akan mengarah pada perilaku ini:

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

Aturan:

  1. Harus bekerja pada mesin Linux, di mana pengguna tidak melakukan root tetapi diizinkan untuk menggunakan sudo.
  2. Tidak boleh mengatakan Okayperintah make yang lebih pendek (mis sudo make sandwich.).
  3. Perintah kedua harus bekerja karena sudo, bukan karena doa kedua.

Pedoman:

  1. Tetap singkat (bagaimanapun juga, ini adalah situs Golf Code).
  2. Akan lebih baik jika itu benar-benar membuat sandwich.
  3. Cobalah untuk menyembunyikan dengan cerdik mengapa sudoada perbedaan.

Pemenang akan ditentukan oleh suara.

ugoren
sumber
@ardnew, sayangnya, saya secara khusus meminta untuk menulis makefile, yang, saya pikir, membatalkan solusi berdasarkan patching make.
ugoren
sepenuhnya setuju, @ugoren. tidak bermaksud untuk komentar itu untuk mengabaikan tantangan atau menyarankan solusi
ardnew

Jawaban:

12

Oke, saya akan gigit. Ini tidak selalu mematuhi pedoman # 3, tetapi melakukan pekerjaan yang adil pada dua pedoman lainnya. Ini juga membersihkan setelah itu sendiri, sebagaimana pembuat sandwich yang baik seharusnya.

.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

(Kurang buggy, dan mudah-mudahan sedikit kurang membosankan, daripada pengajuan awal saya.)

kotak roti
sumber
Sepertinya itu melanggar aturan # 2 - sudo make me sandwich.
ugoren
&& test -e ./a
luser droog
Argh, kamu benar. Versi ini harus melakukan pekerjaan yang lebih baik dalam mengamati aturan.
kotak roti
1
Anda tentu memiliki nama yang paling tepat, @breadbox
ardnew
9

Solusi yang cukup ringkas yang mengabaikan pedoman # 2 (127 karakter, termasuk beberapa spasi putih yang tidak perlu). Saya mengikuti praktik breadbox untuk membersihkan diri sendiri. Jangan letakkan file lain di direktori yang sama dengan makefile! Perhatikan juga bahwa makefile harus dipanggil Makefile, nama lain tidak akan berfungsi.

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

Pemakaian:

$ 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

Saya suka cara yang satu ini berkaitan dengan pedoman # 3. Hanya satu tekan saja yang Shiftmembuat perbedaan.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
3

Solusi ini tidak mematuhi pedoman # 2 - atau tidak jelas berbentuk sandwich? Saya pergi pada semacam tema palindrome di awal, tetapi saya hanya bisa menemukan begitu banyak cara untuk membuat garis simetris tanpa menggunakan lumpuh real code # ecod laer. Saya tidak menganggap serius panduan # 1, estetika lebih utama.

Ingat bahwa itu adalah makefile; 3 baris berturut-turut dimulai dengan if, rmdan echomulai dengan tab. Garis lekukan lainnya dimulai dengan spasi.

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

Penggunaan (perintah dapat dikeluarkan dalam urutan apa pun):

$ 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

Adapun pedoman # 3, ini tidak disembunyikan dengan cerdik, hanya sedikit aneh. Beberapa petunjuk:

Ada dua tes yang berbeda: satu pencarian SUDO_USER, dan satu tes apakah id -ucetakan 0. Do Anda melihat mengapa What?ini tidak dicetak untuk root? Apakah Anda melihat bagaimana kurangnya SUDO_USERpenyebab Okayuntuk tidak dicetak?

Gilles 'SANGAT berhenti menjadi jahat'
sumber
2

Ini adalah langkah pertama menggunakan teknik yang berbeda dan lebih sederhana:

.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

Saya cukup yakin ada lebih banyak yang dapat saya lakukan dengan ini - mendapatkannya untuk menanggapi perintah input lainnya misalnya. Saya harus bekerja pada kebingungan root switch dan pembuatan sandwich yang sebenarnya.

Benediktus
sumber