Arti dari garis “exec tail -n +3 $ 0” dalam file 40_custom


17

Saya mencoba memahami file konfigurasi grub. Jadi, selama proses ini saya menemukan file /etc/grub.d/40_custom . File saya berisi baris-baris berikut:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry "Windows 10" --class windows --class os {
insmod part_msdos
savedefault
insmod ntfs
insmod ntldr
set root='(hd0,msdos1)'
ntldr ($root)/bootmgr
}

karena sistem saya adalah dual boot dan ternyata ini adalah boot loader untuk windows 10.

Pertanyaan saya adalah bagian ini exec tail -n +3 $0.
Jika saya mengartikannya dengan benar, ini berarti mencetak baris terakhir mulai dari baris ke-3 ( +3) file $0. $0tentu saja dalam kasus ini adalah file aktual /etc/grub.d/40_custom .

Jadi, mengapa kita menggunakan perintah ini dalam file 40_custom ? Ketika saya mendapatkannya output akan sama jika ιt dihilangkan sama sekali. Satu-satunya perbedaan yang mungkin saya pikirkan adalah baris pertama yang mengidentifikasi penerjemah:

#!/bin/sh

Tapi sekali lagi itu dijalankan sejak exec tail -n +3 $0mengikutinya. Jadi, apakah ini hanya konvensi (tidak berguna)?

Jawaban:


16

Kuncinya adalah apa yang execdilakukan:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

Ini berarti akan mengganti shell dengan apa pun yang diberikan exec, dalam hal ini tail. Berikut ini contoh tindakannya:

$ cat ~/foo.sh
#!/bin/sh
exec tail -n +3 "$0"
echo foo

$ ./foo.sh
echo foo

Jadi echoperintah tidak dijalankan karena kami telah mengubah shell dan menggunakan tailsebagai gantinya. Jika kami menghapus exec tail:

$ cat ~/foo.sh
#!/bin/sh
echo foo
$ ./foo.sh
foo

Jadi, ini adalah trik rapi yang memungkinkan Anda menulis skrip yang tugasnya hanya menghasilkan isinya sendiri. Agaknya, apa pun panggilan 40_custommengharapkan isinya sebagai output. Tentu saja, ini menimbulkan pertanyaan mengapa tidak tail -n +3 /etc/grub.d/40_customlangsung berlari .

Saya kira jawabannya adalah karena grub menggunakan bahasa scripting sendiri dan ini membuatnya perlu solusi ini.


Jawaban bagus! Tetapi bagaimana jika kita akan menulis #!/bin/tail -n +2sebagai shellbang? Apakah akan mencetak sisa file?
val mengatakan Reinstate Monica

@val coba dan lihat :) Ternyata itu tidak berfungsi sempurna sebagai shebang, -n +2sepertinya ditafsirkan sebagai -n 2dan hanya dua baris terakhir yang dicetak. Itu mungkin layak pertanyaan sendiri.
terdon

3
@val ... perilaku shebang jauh lebih sedikit standar dan portabel daripada yang Anda harapkan. Lihat bagian "interpretasi argumen perintah" dari en.wikipedia.org/wiki/Shebang_(Unix)#Portabilitas
Charles Duffy

@val Itu bekerja di Linux jika Anda menghapus ruang antara ndan +. Paling tidak di Linux, setelah path dan spasi yang dapat dieksekusi, karakter berikut diperlakukan sebagai argumen tunggal. Jadi dengan spasi, tail melihatnya dan mungkin memutuskan untuk menghapus -nargumen awalan apa pun yang tidak valid (dalam hal ini, spasi dan a +) sampai mencapai nomor. Namun, seperti kata Charles Duffy, cara mereka saat ini mungkin lebih mudah dibawa ke Unix lain.
JoL

1
@fluffy Mereka dapat menggunakan di sini doc. Lihat tautan dari dokumentasi Fedora dalam jawaban saya. Mereka menggunakan tepat di cat <<EOF ...EOFsana
Sergiy Kolodyazhnyy

9

Direktori ini /etc/grub.d/berisi banyak file yang dapat dieksekusi (biasanya skrip shell, tetapi semua jenis yang dapat dieksekusi juga dimungkinkan). Setiap kali grub-mkconfigdieksekusi (misalnya jika Anda menjalankan update-grub, tetapi juga ketika Anda menginstal paket kernel yang diperbarui, yang biasanya memiliki kait pasca-instalasi yang memberitahu manajer paket untuk memperbarui grub.cfg), semuanya dijalankan dalam urutan abjad. Keluaran mereka semuanya digabungkan, dan berakhir di file /boot/grub/grub.cfg, dengan header bagian rapi yang menunjukkan bagian mana yang berasal dari /etc/grub.d/file yang mana .

File yang satu ini 40_custom ini dirancang untuk memungkinkan Anda dengan mudah menambahkan entri / baris ke dalam grub.cfghanya dengan mengetik / menempelkannya ke file ini. Skrip lain dalam direktori yang sama melakukan tugas yang lebih kompleks seperti mencari kernel atau sistem operasi non-linux dan membuat entri menu untuk mereka.

Untuk memungkinkan grub-mkconfiguntuk memperlakukan semua file dengan cara yang sama (mengeksekusi dan mengambil output), 40_customadalah skrip dan menggunakan exec tail -n +3 $0mekanisme ini untuk menampilkan kontennya (minus "header"). Jika itu bukan file yang dapat dieksekusi, update-grubperlu pengecualian kode-keras khusus untuk mengambil konten teks literal file ini alih-alih mengeksekusi seperti yang lainnya. Tetapi bagaimana jika Anda (atau pembuat distribusi linux lain) ingin memberikan nama yang berbeda pada file ini? Atau bagaimana jika Anda tidak tahu tentang pengecualian dan membuat skrip shell bernama 40_custom?

Anda dapat membaca lebih lanjut tentang grub-mkconfigdan /etc/grub.d/*dalam Manual GRU GNU (meskipun sebagian besar berbicara tentang opsi yang dapat Anda atur /etc/default/grub), dan harus ada file /etc/grub.d/READMEyang menyatakan bahwa file-file ini dieksekusi untuk membentuk grub.cfg.


1
Sementara jawaban terdon menjelaskan bagaimana garis bekerja, yang satu ini memberikan alasan desain yang lebih masuk akal mengapa GRUB melakukan hal-hal seperti ini.
JoL

Jawaban yang bagus Untuk poin Anda tentang pengecualian khusus - pengecualian "sederhana" bisa saja memiliki dua direktori misalnya /etc/grub.d/execuntuk file / skrip exectuable, dan /etc/grub.d/staticuntuk file teks biasa, atau beberapa indikator lain untuk membedakan ini. Namun, ini adalah keputusan desain yang mereka ikuti.
Stobor

3

TL; DR : ini adalah trik untuk menyederhanakan menambahkan entri baru ke file

Seluruh poin dijelaskan di salah satu halaman Wiki Ubuntu di grub :

  1. Hanya file yang dapat dieksekusi yang menghasilkan keluaran ke grub.cfg selama eksekusi pembaruan-grub.

Keluaran skrip dalam /etc/grub.d/menjadi isi grub.cfgfile.

Sekarang, apa fungsinya exec? Itu dapat kembali kawat output untuk seluruh skrip atau jika perintah disediakan - perintah yang disebutkan menyalip dan menggantikan proses skrip. Apa yang dulu merupakan skrip shell dengan PID 1234 sekarang adalah tailperintah dengan PID 1234.

Sekarang Anda sudah tahu bahwa tail -n +3 $0mencetak semuanya setelah baris ke-3 dalam skrip itu sendiri. Jadi mengapa kita perlu melakukan ini? Jika grub hanya peduli dengan output, kita juga bisa

cat <<EOF
    menuentry {
    ...
    }
EOF

Bahkan, Anda akan menemukan cat <<EOFcontoh di dokumentasi Fedora , meskipun untuk tujuan yang berbeda. Intinya ada di komentar - kemudahan penggunaan bagi pengguna:

# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.

Dengan exectrik, Anda tidak perlu tahu apa fungsinya cat <<EOF(spoiler, begitulah namanya sini-doc ), atau Anda harus ingat untuk menambahkannya EOFpada baris terakhir. Cukup tambahkan menu masuk ke file dan selesai dengan itu. Plus, jika Anda membuat skrip menambahkan menu masuk, Anda bisa menambahkan melalui>> shell ke file ini.

Lihat juga:


Tetapi mengapa tidak meminta grub membaca file secara langsung? Apakah Anda tahu mengapa mereka memilih untuk membuatnya dieksekusi? Akan jauh lebih mudah untuk menjadikannya sebagai file teks sederhana yang dibaca oleh proses apa pun yang menghasilkan menu, tetapi sebaliknya mereka memilih untuk membuatnya dapat dieksekusi dan menambahkan ini (rapi) tetapi solusi yang rumit. Apakah karena grub memiliki bahasa skrip sendiri seperti yang saya tempatkan dalam jawaban saya?
terdon

@terdon Saya tidak berpikir ini ada hubungannya dengan bahasa grub itu sendiri. Anda tidak perlu #!/bin/shdalam hal itu. Saya menduga ini hanyalah alasan historis (dibawa dari basis kode PUPA ) dan keputusan desain yang terinspirasi oleh jenis skrip SysV.
Sergiy Kolodyazhnyy

@terdon Ini sebenarnya menginspirasi pertanyaan: unix.stackexchange.com/q/492966/85039
Sergiy Kolodyazhnyy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.