Anda dapat melewati semua jalan ke Perbaikan Cepat tetapi itu belum tentu pilihan terbaik. Jadi saya sarankan membaca ini dulu.
rc.local
tidak mentolerir kesalahan.
rc.local
tidak menyediakan cara untuk secara cerdas pulih dari kesalahan. Jika ada perintah yang gagal, itu berhenti berjalan. Baris pertama #!/bin/sh -e
,, menyebabkannya dieksekusi di shell yang dipanggil dengan -e
flag. The -e
bendera adalah apa yang membuat script (dalam hal ini, rc.local
) berhenti berjalan pertama kalinya perintah gagal di dalamnya.
Anda ingin rc.local
bersikap seperti ini. Jika perintah gagal, Anda tidak ingin melanjutkan dengan apa pun perintah startup lain yang mungkin bergantung padanya telah berhasil.
Jadi jika ada perintah gagal, perintah selanjutnya tidak akan berjalan. Masalahnya di sini adalah bahwa /script.sh
tidak berjalan (bukan itu gagal, lihat di bawah), jadi kemungkinan besar beberapa perintah sebelum gagal. Tapi yang mana?
Apakah itu /bin/chmod +x /script.sh
?
Tidak.
chmod
berjalan dengan baik setiap saat. Asalkan sistem file yang berisi /bin
sudah dipasang, Anda dapat menjalankan /bin/chmod
. Dan /bin
sudah terpasang sebelum rc.local
berjalan.
Saat dijalankan sebagai root, /bin/chmod
jarang gagal. Ini akan gagal jika file yang dioperasikan itu hanya-baca, dan mungkin gagal jika sistem file yang aktif tidak mendukung izin. Tidak ada kemungkinan di sini.
Ngomong-ngomong, sh -e
adalah satu - satunya alasan itu sebenarnya akan menjadi masalah jika chmod
gagal. Saat Anda menjalankan file skrip dengan secara eksplisit memanggil penerjemahnya, tidak masalah jika file tersebut ditandai dapat dieksekusi. Hanya jika dikatakan /script.sh
bit file yang dapat dieksekusi. Karena dikatakan sh /script.sh
, tidak (kecuali tentu saja /script.sh
memanggil dirinya sendiri saat berjalan, yang bisa gagal karena tidak dapat dieksekusi, tetapi tidak mungkin itu menyebut dirinya).
Jadi apa yang gagal?
sh /home/incero/startup_script.sh
gagal. Hampir pasti.
Kami tahu itu berjalan, karena itu diunduh /script.sh
.
(Kalau tidak, akan penting untuk memastikan itu berjalan, kalau-kalau entah bagaimana /bin
tidak di PATH - rc.local
tidak harus memiliki yang sama PATH
seperti yang Anda miliki ketika Anda login. Jika /bin
tidak di rc.local
jalur, ini akan perlu sh
dijalankan sebagai /bin/sh
. Karena itu berjalan, /bin
adalah di PATH
, yang berarti Anda dapat menjalankan perintah lain yang berada di /bin
, tanpa sepenuhnya memenuhi syarat nama mereka. Misalnya, Anda dapat menjalankan hanya chmod
daripada /bin/chmod
. Namun, sesuai dengan gaya Anda di rc.local
, saya telah menggunakan nama yang sepenuhnya memenuhi syarat untuk semua perintah kecuali sh
, setiap kali saya menyarankan Anda menjalankannya.)
Kita bisa yakin /bin/chmod +x /script.sh
tidak pernah berlari (atau Anda akan melihat bahwa /script.sh
itu dieksekusi). Dan kita tahu sh /script.sh
juga tidak lari.
Tapi itu diunduh /script.sh
. Berhasil! Bagaimana itu bisa gagal?
Dua Makna Sukses
Ada dua hal berbeda yang mungkin seseorang maksudkan ketika dia mengatakan sebuah perintah berhasil:
- Itu melakukan apa yang Anda inginkan.
- Dilaporkan bahwa itu berhasil.
Demikian juga untuk kegagalan. Ketika seseorang mengatakan sebuah perintah gagal, itu bisa berarti:
- Itu tidak melakukan apa yang Anda inginkan.
- Dilaporkan bahwa itu gagal.
Sebuah skrip yang dijalankan dengan sh -e
, seperti rc.local
, akan berhenti berjalan saat sebuah perintah melaporkan bahwa ia gagal . Tidak ada bedanya apa yang sebenarnya dilakukan perintah.
Kecuali Anda bermaksud startup_script.sh
melaporkan kegagalan saat melakukan apa yang Anda inginkan, ini adalah bug di startup_script.sh
.
- Beberapa bug mencegah skrip melakukan apa yang Anda inginkan. Mereka mempengaruhi apa yang pemrogram sebut efek sampingnya .
- Dan beberapa bug mencegah skrip melaporkan dengan benar apakah berhasil atau tidak. Mereka memengaruhi apa yang oleh pemrogram sebut nilai pengembaliannya (yang dalam hal ini adalah status keluar ).
Kemungkinan besar startup_script.sh
melakukan semua yang seharusnya, kecuali melaporkan bahwa itu gagal.
Bagaimana Keberhasilan atau Kegagalan Dilaporkan
Skrip adalah daftar nol atau lebih perintah. Setiap perintah memiliki status keluar. Dengan asumsi tidak ada kegagalan dalam menjalankan skrip (misalnya, jika penerjemah tidak dapat membaca baris skrip berikutnya saat menjalankan skrip), status keluar dari skrip adalah:
0
(berhasil) jika skrip kosong (mis., tidak punya perintah).
N
, jika skrip berakhir sebagai hasil dari perintah , di mana ada beberapa kode keluar.exit N
N
- Kode keluar dari perintah terakhir yang dijalankan dalam skrip, jika tidak.
Ketika sebuah executable berjalan, ia melaporkan kode keluarnya sendiri - itu bukan hanya untuk skrip. (Dan secara teknis, kode keluar dari skrip adalah kode keluar yang dikembalikan oleh shell yang menjalankannya.)
Sebagai contoh, jika suatu program C diakhiri dengan exit(0);
, atau return 0;
dalam main()
fungsinya, kode 0
tersebut diberikan kepada sistem operasi, yang menyediakannya untuk proses pemanggilan (yang mungkin, misalnya, adalah cangkang dari mana program dijalankan).
0
berarti program berhasil. Setiap angka lainnya berarti gagal. (Dengan cara ini, angka-angka yang berbeda kadang-kadang dapat merujuk pada alasan berbeda mengapa program gagal.)
Perintah Dimaksudkan untuk Gagal
Kadang-kadang, Anda menjalankan program dengan maksud bahwa itu akan gagal. Dalam situasi ini, Anda mungkin menganggap kegagalannya sebagai keberhasilan, meskipun itu bukan bug yang dilaporkan kegagalan program. Misalnya, Anda dapat menggunakan rm
file yang Anda curigai tidak ada, hanya untuk memastikan itu dihapus.
Sesuatu seperti ini mungkin terjadi startup_script.sh
, tepat sebelum berhenti berjalan. The perintah terakhir untuk dijalankan dalam script mungkin melaporkan kegagalan (meskipun yang "gagal" mungkin benar-benar baik atau bahkan perlu), yang membuat kegagalan laporan skrip.
Tes Dimaksudkan untuk Gagal
Salah satu jenis perintah khusus adalah tes , yang saya maksudkan perintah dijalankan untuk nilai kembalinya daripada efek sampingnya. Artinya, tes adalah perintah yang dijalankan sehingga status keluarnya dapat diperiksa (dan ditindaklanjuti).
Misalnya, saya lupa jika 4 sama dengan 5. Untungnya, saya tahu skrip shell:
if [ 4 -eq 5 ]; then
echo "Yeah, they're totally the same."
fi
Di sini, tes [ -eq 5 ]
gagal karena ternyata 4 ≠ 5 setelah semua. Itu tidak berarti tes tidak dilakukan dengan benar; itu benar. Tugasnya adalah memeriksa apakah 4 = 5, lalu melaporkan keberhasilan jika demikian, dan gagal jika tidak.
Anda lihat, dalam skrip shell, kesuksesan juga bisa berarti benar , dan kegagalan juga bisa berarti salah .
Meskipun echo
pernyataan itu tidak pernah berjalan, if
blok secara keseluruhan tidak mengembalikan kesuksesan.
Namun, seharusnya saya menulisnya lebih pendek:
[ 4 -eq 5 ] && echo "Yeah, they're totally the same."
Ini adalah istilah umum. &&
adalah boolean dan operator. Sebuah &&
ekspresi, yang terdiri dari &&
dengan pernyataan di kedua sisi, kembali palsu (kegagalan) kecuali kedua belah pihak kembali benar (sukses). Sama seperti normal dan .
Jika seseorang bertanya kepada Anda, "apakah Derek pergi ke mal dan berpikir tentang kupu-kupu?" dan Anda tahu Derek tidak pergi ke mal, Anda tidak perlu repot mencari tahu jika dia memikirkan seekor kupu-kupu.
Begitu pula jika perintah di sebelah kiri &&
gagal (false), seluruh &&
ekspresi langsung gagal (false). Pernyataan di sisi kanan &&
tidak pernah berjalan.
Di sini, [ 4 -eq 5 ]
berjalan. Itu "gagal" (return false). Jadi seluruh &&
ekspresi gagal. echo "Yeah, they're totally the same."
tidak pernah berlari. Segala sesuatu berperilaku sebagaimana mestinya, tetapi perintah ini melaporkan kegagalan (meskipun persyaratan yang setara di if
atas melaporkan keberhasilan).
Jika itu adalah pernyataan terakhir dalam sebuah skrip (dan skrip itu sampai ke sana, daripada berhenti di beberapa titik sebelum itu), seluruh skrip akan melaporkan kegagalan .
Ada banyak tes selain ini. Misalnya, ada tes dengan ||
("atau"). Namun, contoh di atas harus cukup untuk menjelaskan tes apa, dan memungkinkan Anda untuk secara efektif menggunakan dokumentasi untuk menentukan apakah pernyataan / perintah tertentu adalah tes.
sh
vs. sh -e
, Ditinjau kembali
Sejak itu #!
baris (lihat juga pertanyaan ini ) di bagian atas /etc/rc.local
memiliki sh -e
, sistem operasi berjalan script seolah-olah itu yang dipanggil dengan perintah:
sh -e /etc/rc.local
Sebaliknya, skrip Anda yang lain, seperti startup_script.sh
, berjalan tanpa itu -e
bendera:
sh /home/incero/startup_script.sh
Akibatnya mereka tetap berjalan bahkan ketika sebuah perintah di dalamnya melaporkan kegagalan.
Ini normal dan bagus. rc.local
harus dipanggil dengan sh -e
dan sebagian besar skrip lainnya - termasuk sebagian besar skrip dijalankan oleh - rc.local
seharusnya tidak.
Pastikan untuk mengingat perbedaannya:
Skrip dijalankan dengan sh -e
kegagalan pelaporan yang keluar pertama kali sebuah perintah yang berisi kegagalan pelaporan.
Seolah-olah skrip adalah perintah panjang tunggal yang terdiri dari semua perintah dalam skrip yang digabungkan &&
operator.
Skrip dijalankan dengan sh
(tanpa -e
) terus berjalan sampai mereka mendapatkan perintah yang mengakhiri (keluar dari) mereka, atau sampai akhir skrip. Keberhasilan atau kegagalan setiap perintah pada dasarnya tidak relevan (kecuali perintah berikutnya memeriksanya). Script keluar dengan status keluar dari menjalankan perintah terakhir.
Setelah Membantu Skrip Anda Memahami Ini Bukan Kegagalan
Bagaimana Anda bisa menjaga agar skrip Anda tidak gagal ketika gagal?
Anda melihat apa yang terjadi sebelum itu selesai berlari.
Jika suatu perintah gagal ketika seharusnya berhasil, cari tahu mengapa, dan perbaiki masalahnya.
Jika suatu perintah gagal, dan itu adalah hal yang benar terjadi, maka cegah status kegagalan itu agar tidak menyebar.
Salah satu cara untuk menjaga agar status kegagalan tidak diperbanyak adalah dengan menjalankan perintah lain yang berhasil. /bin/true
tidak memiliki efek samping dan melaporkan keberhasilan (seperti halnya/bin/false
tidak melakukan apa pun dan juga gagal).
Cara lain adalah memastikan skrip diakhiri oleh exit 0
.
Itu belum tentu sama dengan exit 0
berada di akhir skrip. Misalnya, mungkin ada if
blok-di mana skrip keluar di dalamnya.
Yang terbaik untuk mengetahui apa yang menyebabkan skrip Anda melaporkan kegagalan, sebelum membuatnya melaporkan keberhasilan. Jika itu benar-benar gagal dalam beberapa hal (dalam arti tidak melakukan apa yang Anda inginkan), Anda tidak benar-benar ingin melaporkan kesuksesan.
Perbaikan Cepat
Jika Anda tidak dapat membuat startup_script.sh
keluar pelaporan berhasil, Anda dapat mengubah perintah rc.local
yang menjalankannya, sehingga perintah melaporkan keberhasilan meskipun startup_script.sh
tidak.
Saat ini Anda memiliki:
sh /home/incero/startup_script.sh
Perintah ini memiliki efek samping yang sama (yaitu, efek samping dari menjalankan startup_script.sh
), tetapi selalu melaporkan keberhasilan:
sh /home/incero/startup_script.sh || /bin/true
Ingat, lebih baik untuk mengetahui mengapa startup_script.sh
melaporkan kegagalan, dan memperbaikinya.
Cara Kerja Perbaikan Cepat
Ini sebenarnya adalah contoh dari ||
tes, tes atau .
Misalkan Anda bertanya apakah saya mengeluarkan sampah atau menyikat burung hantu. Jika saya mengeluarkan sampah, saya bisa jujur mengatakan "ya," bahkan jika saya tidak ingat apakah saya menyapu burung hantu atau tidak.
Perintah di sebelah kiri ||
menjalankan. Jika berhasil (benar), maka sisi kanan tidak harus berjalan. Jadi jika startup_script.sh
laporan berhasil, makatrue
perintah tidak pernah berjalan.
Namun, jika startup_script.sh
melaporkan kegagalan [saya tidak mengeluarkan sampah] , maka hasil dari /bin/true
[jika saya menyikat burung hantu] penting.
/bin/true
selalu mengembalikan kesuksesan (atau benar , seperti yang kadang-kadang kita sebut itu). Akibatnya, seluruh perintah berhasil, dan perintah selanjutnya rc.local
dapat dijalankan.
Catatan tambahan tentang keberhasilan / kegagalan, benar / salah, nol / bukan nol.
Jangan ragu untuk mengabaikan ini. Anda mungkin ingin membaca ini jika Anda memprogram dalam lebih dari satu bahasa (yaitu, bukan hanya shell scripting)
Ini adalah titik kebingungan besar bagi skrip shell yang menggunakan bahasa pemrograman seperti C, dan bagi programmer C yang menggunakan skrip shell, untuk menemukan:
Dalam skrip shell:
- Nilai pengembalian
0
berarti kesuksesan dan / atau benar .
- Nilai pengembalian sesuatu selain
0
berarti kegagalan dan / atau salah .
Dalam pemrograman C:
- Nilai pengembalian
0
berarti false ..
- Nilai pengembalian sesuatu selain
0
berarti benar .
- Tidak ada aturan sederhana untuk apa yang berarti kesuksesan dan apa yang berarti kegagalan. Terkadang
0
berarti sukses, di lain waktu itu berarti kegagalan, di lain waktu itu berarti jumlah dari dua angka yang baru Anda tambahkan adalah nol. Nilai pengembalian dalam pemrograman umum digunakan untuk memberi sinyal berbagai macam jenis informasi.
- Status keluar numerik suatu program harus menunjukkan keberhasilan atau kegagalan sesuai dengan aturan untuk skrip shell. Artinya, meskipun
0
berarti salah dalam program C Anda, Anda masih membuat program Anda kembali 0
sebagai kode keluarnya jika Anda ingin melaporkannya berhasil (yang shell kemudian tafsirkan sebagai benar ).
incero
(saya berasumsi itu nama pengguna) adalah administrator , dan dengan demikian diizinkan untuk menjalankan perintah apa punroot
(dengan memasukkan kata sandi pengguna mereka sendiri), itu tidak super tidak aman dan mengerikan . Jika Anda menginginkan solusi lain, saya sarankan memposting pertanyaan baru tentang ini . Satu masalah adalah mengapa perintah dirc.local
tidak berjalan (dan Anda juga memeriksa untuk melihat apa yang akan terjadi jika Anda membuatnya terus berjalan). Sekarang Anda memiliki masalah yang berbeda: Anda ingin agar mesin terhubung dengan jaringan sebelumrc.local
dijalankan, atau menjadwalkan pengoperasianstartup_script.sh
nanti./usr/bin/sudo service networking restart
ke skrip startup sebelum perintah wget menghasilkan wget kemudian berfungsi.rc.local
Anda dapat (dalam varian Unix yang saya gunakan) mengesampingkan perilaku default dengan mengubah:
Untuk:
Di awal skrip. Bendera "-e" memerintahkan sh untuk keluar pada kesalahan pertama. Nama panjang bendera itu adalah "errexit", jadi garis aslinya setara dengan:
sumber
-e
karya pada jessie raspbian.-e
sana karena suatu alasan. Aku tidak akan melakukan itu jika aku jadi kamu. Tapi aku bukan orang tuamu.ubah baris pertama dari:
#!/bin/sh -e
ke!/bin/sh -e
sumber
#!
adalah yang benar. (Setidaknya,#!
bagian itu benar. Dan sisanya biasanya berfungsi dengan baik untuk, untukrc.local
.) Lihat artikel ini dan pertanyaan ini . Bagaimanapun, selamat datang di Tanya Ubuntu!