40_custom dosyasındaki “exec tail -n +3 $ 0” satırının anlamı


17

Grub yapılandırma dosyalarını anlamaya çalışıyorum. Bu işlem sırasında /etc/grub.d/40_custom dosyasıyla karşılaştım . Dosyam aşağıdaki satırları içeriyor:

#!/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
}

benim sistem çift önyükleme olduğu ve görünüşe göre bu windows 10 için önyükleme yükleyici.

Benim sorum bu kısım exec tail -n +3 $0.
Doğru bir şekilde deşifre edersem, bu sadece +3dosyanın 3. satırından ( ) başlayarak son satırları yazdırmak anlamına gelir $0. $0tabii ki bu durumda asıl dosya /etc/grub.d/40_custom .

Peki, bu komutu neden 40_custom dosyasında kullanıyoruz? Aldığım zaman çıktı tamamen çıkarılsaydı aynı olurdu. Düşünebileceğim tek farklı yorumlayıcıyı tanımlayan 1. satırdır:

#!/bin/sh

Ama sonra tekrardan beri yürütülür exec tail -n +3 $0. Peki, bu sadece (işe yaramaz) bir toplantı mı?

Yanıtlar:


16

Hile ne execyapar:

$ 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.

Bu, kabuğun execbu durumda verilenle değiştirileceği anlamına gelir tail. İşte bunun bir örneği:

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

$ ./foo.sh
echo foo

Bu nedenle, echokabuğu değiştirdiğimiz ve tailbunun yerine kullandığımız için komut yürütülmez . Kaldırırsak exec tail:

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

Yani, bu, tek işi kendi içeriğini çıkarmak olan bir komut dosyası yazmanıza izin veren düzgün bir numaradır. Muhtemelen, ne diyorsa40_custom , içeriği çıktı olarak beklenir. Tabii ki, bu sadece tail -n +3 /etc/grub.d/40_customdoğrudan koşmamanın nedenini soruyor .

Cevabı tahmin ediyorum, çünkü grub kendi kodlama dilini kullanıyor ve bu da bu geçici çözümü gerektiriyor.


Güzel cevap! Ama ya #!/bin/tail -n +2bir mermi olarak yazacaksak? Dosyanın geri kalanını yazdıracak mı?
val diyor Reinstate Monica

@val denemek ve görmek :) Mükemmel bir shebang olarak işe yaramıyor gibi -n +2görünüyor, gibi yorumlanır -n 2ve sadece son iki satır yazdırılır. Bu muhtemelen kendi sorusuna değer.
terdon

3
@val ... shebang davranış beklediğinizden çok daha az standart ve taşınabilir. Tr.wikipedia.org/wiki/Shebang_(Unix)#Portability
Charles Duffy

@val nve ile arasındaki boşluğu kaldırırsanız Linux'ta çalışır +. En azından Linux'ta, yürütülebilir yol ve boşluktan sonra, aşağıdaki karakterler tek bir bağımsız değişken olarak ele alınır. Böylece boşlukla kuyruk onu görür ve muhtemelen geçersiz önek -nargümanının sahip olduğu her şeyi (bu durumda boşluk ve a +) sayıya ulaşana kadar kaldırmaya karar verir . Bununla birlikte, Charles Duffy'nin dediği gibi, bunu yapmanın şu andaki yolu muhtemelen diğer Unices için daha taşınabilir.
JoL

1
@fluffy Onlar yapabilirsiniz burada doktor kullanın. Cevabımdaki Fedora belgelerindeki bağlantıya bakın. Tam olarak cat <<EOF ...EOForada kullanıyorlar
Sergiy Kolodyazhnyy

9

Dizin /etc/grub.d/birçok çalıştırılabilir dosya içerir (genellikle kabuk komut dosyalarıdır, ancak diğer yürütülebilir türler de mümkündür). Ne grub-mkconfigzaman çalıştırılırsa (örneğin, çalıştırırsanız update-grub, ancak genellikle paket yöneticisine güncellemesini söyleyen bir yükleme sonrası kancası olan güncelleştirilmiş bir çekirdek paketi yüklediğinizdegrub.cfg ), bunların tümü alfabetik sırada yürütülür. Çıktılarının tümü birleştirilir ve dosyada /boot/grub/grub.cfg, hangi bölümün hangi /etc/grub.d/dosyadan geldiğini gösteren düzgün bölüm başlıklarıyla sonuçlanır .

Bu özel dosya 40_custom, girişleri / satırları kolayca grub.cfgbu dosyaya yazarak / yapıştırarak kolayca eklemenizi sağlamak için tasarlanmıştır . Aynı dizindeki diğer komut dosyaları, çekirdek veya linux dışı işletim sistemleri aramak ve bunlar için menü girişleri oluşturmak gibi daha karmaşık görevleri yerine getirir.

grub-mkconfigTüm bu dosyaları aynı şekilde işlemeye izin vermek için (çalıştır ve çıktıyı al), 40_custombir betiktir ve exec tail -n +3 $0içeriğini çıkarmak için bu mekanizmayı kullanır (eksi "başlık"). Yürütülebilir bir dosya update-grubolmasaydı, diğer tüm dosyalar gibi yürütmek yerine, bu dosyanın gerçek metin içeriğini almak için özel bir sabit kodlu özel durum gerekir. Peki ya siz (ya da başka bir linux dağıtımının yapımcıları) bu dosyaya farklı bir ad vermek isterseniz? Ya da istisna hakkında bilginiz yoksa ve adlı bir kabuk betiği oluşturduysanız 40_custom?

Daha okuyabilirsiniz grub-mkconfigve /etc/grub.d/*içinde Manuel GNU GRUB (Eğer ayarlayabileceğiniz seçenekler hakkında daha çok konuşur rağmen /etc/default/grub) ve ayrıca bir dosya olmalıdır /etc/grub.d/READMEbu dosyaların idam olduğunu devletler oluşturmak üzere o grub.cfg.


1
Terdon'un cevabı, hattın nasıl çalıştığını açıklarken, bu, GRUB'un işleri neden bu şekilde yaptığı için daha makul bir tasarım nedeni veriyor.
JoL

Mükemmel cevap. Özel istisnalar hakkındaki görüşünüze göre - "daha basit" bir istisna, örneğin /etc/grub.d/execexectuable dosyaları / komut dosyaları ve /etc/grub.d/staticdüz metin dosyaları veya bunları ayırt etmek için başka bir gösterge olmak üzere iki dizine sahip olabilirdi . Ancak, bu tasarım kararını verdiler.
Stobor

3

TL; DR : dosyaya yeni girişler eklemeyi basitleştirmek için bir hile

Bütün mesele, Ubuntu'nun Wiki sayfalarından birinde grupta açıklanmıştır :

  1. Güncelleme grubunun yürütülmesi sırasında grub.cfg dosyasına yalnızca yürütülebilir dosyalar çıktı üretir.

Komut dosyalarının çıktısı dosyanın /etc/grub.d/içeriği olur grub.cfg.

Şimdi ne yapıyorexec ? Tüm komut dosyası için çıktıyı yeniden kablolayabilir veya bir komut verilirse, söz konusu komut komut dosyası işlemini alır ve değiştirir. Bir zamanlar PID 1234 ile kabuk betiği olan PID 1234 ile tailkomut.

Artık biliyorsunuz ki, tail -n +3 $0her şey komut dosyasındaki 3. satırdan sonra yazdırılıyor. Peki bunu neden yapmamız gerekiyor? Grub sadece çıktıyı önemsiyorsa, biz de yapabiliriz

cat <<EOF
    menuentry {
    ...
    }
EOF

Aslında, farklı bir amaç olsa da cat <<EOF, Fedora belgelerinde örnek bulacaksınız . Bütün mesele yorumlarda - kullanıcılar için kullanım kolaylığı:

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

execHile ile ne cat <<EOFyaptığını bilmek zorunda değilsiniz (spoiler, burada-doc olarak adlandırılır ) veya eklemeyi hatırlamanız gerekmez.EOF son satırında. Sadece dosyaya menü girişi ekleyin ve onunla bitirin. Ayrıca, bir menü >>girişi ekliyorsanız, bu dosyaya kabuk üzerinden ekleyebilirsiniz .

Ayrıca bakınız:


Ama neden grub dosyaları doğrudan okumuyor? Onları neden çalıştırılabilir yapmayı seçtiklerine dair bir fikrin var mı? Onları menü üreten herhangi bir işlem tarafından okunan basit metin dosyaları olarak sahip olmak çok daha basit olurdu, ancak bunun yerine onları yürütülebilir hale getirmeyi seçtiler ve bu (düzgün) ancak karmaşık geçici çözümü eklediler. Cevabımda poz verdiğimde grubun kendi komut dosyası dili olduğu için mi?
terdon

@terdon Bunun grub dilinin kendisi ile bir şey yapması gerektiğini düşünmüyorum. Bu #!/bin/shdurumda ihtiyacınız olmaz . Bunun sadece tarihsel bir neden ( PUPA kod tabanından taşınan ) ve SysV tür komut dosyalarından esinlenen bir tasarım kararı olduğundan şüpheleniyorum .
Sergiy Kolodyazhnyy

@terdon Bu aslında bir soruya ilham verdi: unix.stackexchange.com/q/492966/85039
Sergiy Kolodyazhnyy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.