Rc.local neden tüm komutlarımı çalıştırmıyor ve bu konuda ne yapabilirim?


35

Aşağıdaki rc.localbetiğe sahibim :

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

sh /home/incero/startup_script.sh
/bin/chmod +x /script.sh
sh /script.sh

exit 0

İlk satır, startup_script.shaslında üçüncü satırda belirtilen script.shdosyayı indirir /script.sh.

Ne yazık ki, komut dosyasını çalıştırılabilir hale getirmiyor veya komut dosyasını çalıştırmıyor gibi görünüyor. Başladıktan sonra rc.localdosyayı elle çalıştırmak mükemmel çalışıyor. Chmod başlangıçta çalıştırılamaz mı?

Yanıtlar:


70

A Quick Fix'e kadar tamamen atlayabilirsiniz ancak bu mutlaka en iyi seçenek değildir. Bu yüzden önce bütün bunları okumanızı öneriyorum.

rc.local hataları hoş görmez.

rc.localhatalardan akıllıca kurtarmanın bir yolunu sağlamıyor. Herhangi bir komut başarısız olursa, çalışmayı durdurur. İlk satır, bayrakla #!/bin/sh -eçağrılan bir kabukta yürütülmesine neden olur -e. -eBayrak (bu durumda bir komut dosyası kılan rc.localbir komut içindeki başarısız ilk kez yayından).

Böyle rc.localdavranmak istiyorsun . Bir komut başarısız olursa, do not diğer başlatma komutları başaran buna güvenerek olabilir ne olursa olsun devam etmek istiyorum.

Dolayısıyla herhangi bir komut başarısız olursa, sonraki komutlar çalışmayacaktır. Buradaki sorun, /script.shçalışmadı (başarısız oldu, aşağıya bakınız), bu yüzden büyük olasılıkla başarısız önce bazı komuttur. Fakat hangisi?

Öyle miydi /bin/chmod +x /script.sh?

Yok hayır.

chmodherhangi bir zamanda iyi çalışır. İçerdiği dosya sistemi /binmonte edildiyse, çalıştırabilirsiniz /bin/chmod. Ve çalıştırmadan /binönce monte edilir rc.local.

Kök olarak çalıştırdığınızda, /bin/chmodnadiren başarısız olur. Çalıştığı dosya salt okunur ise başarısız olur ve üzerinde çalıştığı dosya sistemi izinleri desteklemiyorsa başarısız olabilir . Burada da muhtemel değil.

Bu arada, başarısız olursa, aslında bir sorun olması sh -eiçin tek nedeni budur chmod. Bir script dosyasını tercümanını açık bir şekilde çalıştırarak çalıştırdığınızda, dosyanın çalıştırılabilir olarak işaretlenmesi önemli değildir. Yalnızca /script.shdosyanın çalıştırılabilir biti olacağı söylenirse . Diyor yana sh /script.sh, öyle değil (tabii sürece /script.sh kendisini çağıran o yürütülebilir olmama gelen başarısız olabilecek şekilde, ishal, ama buna kendisini çağıran düşüktür iken).

Peki ne başarısız oldu?

sh /home/incero/startup_script.shbaşarısız oldu. Neredeyse kesin.

Çalıştığını biliyoruz, çünkü indirildi /script.sh.

(Aksi takdirde, durumunda her nasılsa, bu kaçtın emin olmak için önemli olacağını /bindeğildi PATH - rc.localille aynı bulunmamaktadır PATH. Eğer giriş yaptığınızda olduğu gibi değilse /bindeğildi rc.local'ın yolu, bu gerektirecektir sholarak çalıştırılacak /bin/sh. çalıştırıyordu beri /binolduğu PATH, yeralıyorsunuz diğer komutları çalıştırabilirsiniz yani /bintam isimlerini eleme olmadan. Örneğin, sadece çalıştırabilirsiniz chmodziyade /bin/chmod. Ancak, tarzı doğrultusunda in rc.local, shne zaman çalıştırmanızı öneririm dışında , tüm komutlar için tam olarak nitelenmiş isimler kullandım .)

/bin/chmod +x /script.shAsla kaçmadığımızdan emin olabiliriz (ya /script.shda idam edildiğini göreceksiniz ). Ve biliyoruz ki sh /script.shkaçmadık.

Ama indirildi /script.sh. Başardı! Nasıl başarısız olabilir?

Başarının İki Anlamı

Bir komutun başarılı olduğunu söylediğinde bir insanın ne anlama gelebileceği iki farklı şey vardır:

  1. İstediğini yaptı.
  2. Başardığını bildirdi.

Ve böylece başarısızlık için. Bir kişi bir komutun başarısız olduğunu söylediğinde, bunun anlamı olabilir:

  1. Yapmasını istediğin şeyi yapmadı.
  2. Başarısız olduğunu bildirdi.

sh -eLike ile çalışan bir script , rc.localbir komutun başarısız olduğunu bildirdiği ilk seferde çalışmayı durdurur . Komutun gerçekte yaptıkları arasında bir fark yoktur.

startup_script.shİstediğiniz şeyi yaptığında başarısızlık bildirme niyetinde değilseniz, bu bir hatadır startup_script.sh.

  • Bazı hatalar bir komut dosyasının yapmasını istediğiniz şeyi yapmasını önler. Programcının yan etkileri dediği şeyi etkiler .
  • Bazı hatalar, bir betiğin başarılı olup olmadığını doğru şekilde bildirmesini engeller. Hangi programcıların dönüş değeri olarak adlandırdıklarını etkiler (bu durumda çıkış durumu ).

Başarısız olduğu bildirildi dışındastartup_script.sh , yapılması gereken her şeyi yapmış olması muhtemel .

Başarı veya Başarısızlık Nasıl Bildirilir?

Bir komut dosyası, sıfır veya daha fazla komutun listesidir. Her komutun çıkış durumu vardır. Komut dosyasını çalıştırmada hiçbir başarısızlık olmadığını varsayarak (örneğin, tercüman komut dosyasını çalıştırırken bir sonraki satırı okuyamadıysa), bir komut dosyasının çıkış durumu şöyledir:

  • 0 (basarili) eğer betik boştuysa (yani, komutları yoktu)
  • N, komut dosyası komutun sonucunda sona erdiyse , bazı çıkış kodları nerededir.exit NN
  • Aksi takdirde, kodda çalışan son komutun çıkış kodu.

Bir çalıştırılabilir çalıştırıldığında, kendi çıkış kodunu bildirir - yalnızca komut dosyaları için değil. (Ve teknik olarak, komut dosyalarından çıkış kodları, onları çalıştıran mermilerin döndürdüğü çıkış kodlarıdır.)

Örneğin, bir Cı programı uçları ise exit(0);, ya da return 0;onun içinde main()işlev kodu 0(bu, örneğin, bir program çalıştırıldığı kabuk olabilir) süreci arama ortaya çıkarır, işletim sistemi, verilir.

0programın başarılı olduğu anlamına gelir. Diğer her numara, başarısız olduğu anlamına gelir. (Bu şekilde, farklı sayılar bazen programın başarısız olmasının farklı nedenlerini ifade edebilir.)

Komutlar başarısız oldu

Bazen, programın başarısız olacağı niyeti ile çalışıyorsunuz. Bu durumlarda, programın başarısızlığı rapor ettiği bir hata olmasa da başarısızlığını başarı olarak düşünebilirsiniz. Örneğin, rmzaten silinmediğinden emin olmak için mevcut olmadığını düşündüğünüz bir dosyayı kullanabilirsiniz .

Böyle bir şey, muhtemelen startup_script.shçalışmayı bırakmadan hemen önce oluyor . Vadede son komut komut muhtemelen başarısızlık bildiriyor (olsa bile onun "başarısızlık" tamamen ince ve hatta gerekli olabilir) komut rapor başarısızlık yapar.

Başarısız Olan Testler

Özel bir komut türü bir testtir , bunun anlamı yan etkilerinden ziyade dönüş değeri için bir komut çalıştırmak. Bir test, çıkış durumunun incelenebilmesi (ve buna göre harekete geçilmesi) için yürütülen bir komuttur.

Örneğin, 4'ün 5'e eşit olup olmadığını unuttuğumu varsayalım. Neyse ki, kabuk kodlamasını biliyorum:

if [ 4 -eq 5 ]; then
    echo "Yeah, they're totally the same."
fi

Burada test [ -eq 5 ]başarısız olur, çünkü sonuçta 4 ≠ 5 olur. Bu, testin doğru performans göstermediği anlamına gelmez; o yaptı. İş 4 = 5 olup olmadığını kontrol etmek, ardından öyleyse başarıyı bildirmek ve başarısız olmamaktır.

Görüyorsunuz, kabuk komut dosyasında, başarı aynı zamanda doğru , başarısızlık da yanlış anlamına gelebilir .

İfade echohiçbir zaman yayınlanmasa da, ifbir bütün olarak blok başarı ile sonuçlanır.

Ancak, daha kısa yazacağımı varsayalım:

[ 4 -eq 5 ] && echo "Yeah, they're totally the same."

Bu genel stenodur. &&Bir olan boolean ve operatörü. Her iki taraftaki ifadelerden &&oluşan bir ifade, &&her iki taraf da doğru (başarılı) olmadıkça yanlış (başarısızlık) döndürür. Tıpkı normal bir ve .

Biri size sorarsa, "Derek alışveriş merkezine gidip bir kelebek düşündü mü?" Derek’in alışveriş merkezine gitmediğini biliyorsun, bir kelebek düşünürse, bunu anlamak zorunda değilsin.

Benzer şekilde, solundaki komut &&başarısız olursa (yanlış), tüm &&ifade hemen başarısız olur (yanlış). 'Nın sağ tarafındaki ifade &&asla çalıştırılmaz.

İşte, [ 4 -eq 5 ]koşuyor. "Başarısız" (yanlış döndürüyor). Yani tüm &&ifade başarısız. echo "Yeah, they're totally the same."asla kaçmaz. Her şey olması gerektiği gibi davrandı, ancak bu komut başarısızlık bildirir ( ifyukarıdaki eşdeğer şartların başarılı olduğunu bildirmesine rağmen ).

Eğer bir betiğin son ifadesi bu olsaydı (ve betiğin önündeki bir noktadan çıkmak yerine, betiği ele geçirirse), betiğin tamamı başarısız olur .

Bunun dışında pek çok test var. Örneğin, ||("veya") ile yapılan testler vardır . Bununla birlikte, yukarıdaki örnek, hangi testlerin yapıldığını açıklamak için yeterli olmalı ve belirli bir ifadenin / komutun bir test olup olmadığını belirlemek için belgeleri etkin bir şekilde kullanmanızı mümkün kılmalıdır.

shvs. sh -e, Tekrar Ziyaret Edildi

Yana hattı (ayrıca bkz bu soru üst kısmında) sahiptir bu komutla çağrılan sanki, işletim sistemi komut dosyasını çalıştırır:#!/etc/rc.localsh -e

sh -e /etc/rc.local

Buna karşılık, örneğin diğer komut, startup_script.shçalıştırmak olmadan-e bayrak:

sh /home/incero/startup_script.sh

Sonuç olarak, içlerinde bir komut arızayı bildirdiğinde bile çalışmaya devam ederler.

Bu normal ve iyi. rc.localile çağrılması gereken sh -eve çoğu diğer komut - Çoğu komut dahil ederek koşmak rc.localdeğil --should.

Sadece farkı hatırladığınızdan emin olun:

  • Komut dosyaları, sh -eçıkış raporlama hatası ile çalıştırılır, içerdikleri bir komut raporlama hatasından çıkar.

    Komut dosyası, &&operatörler ile birleştirilmiş komut dosyasındaki tüm komutlardan oluşan tek bir uzun komut gibiydi .

  • sh(With -e) olmadan çalışan scriptler , onları sonlandıran (ondan çıkan) bir komut verene veya betiğin en sonuna kadar devam eder. Her komutun başarısı veya başarısızlığı esasen önemsizdir (bir sonraki komut kontrol etmediği sürece). Komut, son komut çalıştırmasının çıkış durumuyla çıkar.

Komut Dosyanızın Sonuçta Böyle Bir Hata Olmadığını Anlamasına Yardımcı Olma

Senaryonun olmadığında başarısız olduğunu düşünmesini nasıl önleyebilirsin?

Çalışmaya başlamadan hemen önce neler olduğuna bir bak.

  1. Başarılı olması gereken bir komut başarısız olursa, nedenini anlayın ve sorunu düzeltin.

  2. Eğer bir komut başarısız olduysa ve bu gerçekleşmesi gereken doğru şeyse, bu başarısızlık durumunun yayılmasını önleyin.

    • Bir hata durumunun yayılmasını engellemenin bir yolu, başarılı olan başka bir komutu çalıştırmaktır. /bin/trueYan etkisi yoktur ve başarı bildirmez ( /bin/falsehiçbir şey yapmaz ve başarısız olur).

    • Başka bir komut dosyası tarafından sonlandırıldığından emin olmaktır exit 0.

      Bu mutlaka exit 0senaryosun sonunda olduğu gibi değil . Örneğin if, betiğin içinde çıktığı bir -block olabilir .

Betiğinizin başarısız olmasının nedenini, başarı raporunu vermeden önce bilmek en iyisidir. Eğer gerçekten bir şekilde başarısız oluyorsa (yapmak istediğini yapmamak anlamında), gerçekten başarısını rapor etmesini istemezsin.

Hızlı Düzeltme

Eğer yapamıyorsanız startup_script.shçıkış raporlama başarı, komutu değiştirebilirsiniz rc.localo komut raporları başarı olsa böylece, o ishal o startup_script.shyoktu.

Şu anda var:

sh /home/incero/startup_script.sh

Bu komut aynı yan etkilere (yani koşmanın yan etkisi startup_script.sh) sahiptir, ancak her zaman başarı bildirir:

sh /home/incero/startup_script.sh || /bin/true

Unutma, neden startup_script.shhata verdiğini bilmek ve düzeltmek daha iyidir .

Hızlı Onarım Nasıl Çalışır?

Bu aslında bir ||test, bir veya test örneğidir .

Çöpü atıp atmadığımı ya da baykuşu fırçalayıp fırçalamadığımı sorduğunuzu varsayalım. Çöpü dışarı çıkarsaydım, baykuşu fırçalayıp fırçalamadığımı bile hatırlamamama rağmen "evet" diyebilirim.

Solundaki komut ||çalışır. Başarılı olursa (doğru), sağ tarafın koşması gerekmez. Yani startup_script.shbaşarı rapor ederse , truekomut asla çalışmaz.

Ancak, eğer startup_script.shbaşarısızlık rapor ederse [çöpü dışarı çıkarmamışım] , o zaman /bin/true [baykuşu fırçaladıysam] sonucu önemli.

/bin/true(ya da her zaman başarıyı döndüren gerçek bazen dediğimiz gibi). Sonuç olarak, tüm komut başarılı olur ve bir sonraki komut rc.localçalıştırılabilir.

Başarı / başarısızlık, doğru / yanlış, sıfır / sıfırdan başka bir not.

Bunu görmezden gelmekten çekinmeyin. Birden fazla dilde programlıyorsanız, bunu okumak isteyebilirsiniz (örneğin, sadece kabuk komut dosyası değil).

Kabuk kodlayıcıları C gibi programlama dillerini alan ve kabuk programcılığı alan C programcıları için, şunları bulmak için büyük bir karışıklık noktasıdır:

  • Kabuk komut dosyasında:

    1. Döndürme değeri 0aracı başarı ve / veya gerçek .
    2. Başka bir şeyin dönüş değeri, başarısızlık ve / veya yanlış0 anlamına gelir .
  • C programlamada:

    1. Döndürme değeri 0aracı FALSE ..
    2. Dışında bir dönüş değeri 0araçlarının gerçek .
    3. Neyin başarı, neyin başarısızlık olduğu konusunda basit bir kural yoktur. Bazen 0başarı, bazen başarısızlık, bazen de yeni eklediğiniz iki sayının toplamının sıfır olduğu anlamına gelir. Genel programlamadaki dönüş değerleri, çok çeşitli farklı bilgi türlerini işaret etmek için kullanılır.
    4. Bir programın sayısal çıkış durumu, kabuk komut dosyası kurallarına uygun olarak başarı veya başarısızlık belirtmelidir. Yani, 0C programınızda yanlış olsa bile , 0başarılı olduğunu bildirmesini istiyorsanız (hangi kabuk daha sonra doğru olarak yorumlanırsa ) programınızın çıkış kodu olarak geri dönmesini sağlarsınız .

3
vay büyük cevap! Orada bilmediğim bir sürü bilgi var. İlk betiğin sonunda 0 döndürmek, betiğin geri kalanının çalışmasına neden olur (chmod + x'in çalıştığını söyleyebilirim). Ne yazık ki, betiğimdeki / usr / bin / wget komut dosyası script.sh içine konacak bir web sayfasını alamıyor gibi görünüyor. Bu rc.local betiğinin çalıştığı zaman ağın hazır olmadığını tahmin ediyorum. Ağ başladığında ve otomatik olarak başlangıçta çalışacak şekilde bu komutu nereye koyabilirim?
Programcı,

Şu anda sudo visudo çalıştırarak aşağıdaki satırı ekleyerek 'hackledim': username ALL = (ALL) NOPASSWD: TÜM çalışan 'başlangıç ​​uygulamaları' programı (bunun için CLI komutu nedir?) Ve buna startup_script ekleyerek, startupscript şimdi script.sh komutunu sudo komutuyla çalıştırıp, root olarak çalıştırılabilir (artık parola gerektirmez). Hiç şüphe yok ki bu süper güvensiz ve korkunç, ama bu sadece özel bir pxe-boot canlı distro disk içindir.
Programcı

@ Stu2000 Varsayalım incero(kullanıcı adının bu olduğunu sanıyorum) yine de bir yönetici ve bu nedenle süper güvensiz ve korkunçroot olmayan herhangi bir komutu (kendi kullanıcı şifresini girerek) çalıştırmasına izin veriliyor . Başka çözümler istiyorsanız, bunun hakkında yeni bir soru göndermenizi öneririz . Bir sorun, komutların neden çalıştırılmadığıydı (ve onları çalışmaya devam ettirirseniz ne olacağını görmek için kontrol ettiniz). Şimdi farklı bir probleminiz var: makineyi çalıştırmadan önce ağa bağlamak veya daha sonra çalışmasını planlamak istiyorsunuz . rc.localrc.localstartup_script.sh
Eliah Kagan,

1
O zamandan beri bu konuya geri döndüm, rc.local'ı düzenledik ve wget 'işe yaramadı' bulundu. /usr/bin/sudo service networking restartBaşlangıç ​​komut dosyasına wget komutundan önce ekleme , wget ile çalışarak sonuçlandı.
Programcı

3
@EliahKagan harika ayrıntılı cevap. Ben daha iyi bir dokümantasyonla karşılaştımrc.local
souravc

1

(Kullandığım Unix değişkenlerinde), değiştirerek varsayılan davranışı geçersiz kılabilir:

#!/bin/sh -e

Kime:

#!/bin/sh

Senaryonun başında. "-E" bayrağı, ilk hatadan sh çıkmasını söyler. Bu bayrağın uzun adı "errexit" dir, yani orijinal satır şuna eşittir:

#!/bin/sh --errexit

evet, -eraspbian jessie'deki eserlerin kaldırılması .
Oki Erie Rinaldi

-eBir nedeni yoktur. Yerinde olsam bunu yapmazdım. Ama ben senin ailen değilim.
Wyatt8740

-4

ilk satırı değiştir: #!/bin/sh -e den !/bin/sh -e


3
İle sözdizimi #!doğru olanıdır. (En azından, #!parça doğru. Ve gerisi genellikle, için iyi çalışır rc.local.) Bu yazı ve bu soruya bakın . Neyse, Ubuntu'ya sor!
Eliah Kagan,
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.