Ви можете пропустити весь шлях до швидкого виправлення, але це не обов'язково найкращий варіант. Тож рекомендую спочатку все це прочитати.
rc.local
не терпить помилок.
rc.local
не забезпечує способу інтелектуального відновлення після помилок. Якщо якась команда не вдається, вона припиняється. Перший рядок #!/bin/sh -e
викликає його виконання в оболонці, на яку посилається -e
прапор. -e
Прапор, що робить скрипт (в даному випадку rc.local
) перестають працювати в перший раз , команда не буде виконана в ньому.
Ви хочете rc.local
поводитись так. Якщо команда не вдається, ви не хочете, щоб вона продовжувалася з будь-якими іншими командами запуску, можливо, покладаючись на її успіх.
Тож якщо будь-яка команда не вдається, наступні команди не запускаються. Проблема тут полягає в тому, що /script.sh
він не запустився (не те, що він не вдався, див. Нижче), тому, швидше за все, якась команда до того, як вона не вдалася. Але який?
Це було /bin/chmod +x /script.sh
?
Ні.
chmod
працює в будь-який час. За умови встановлення файлової системи, яка містить /bin
, ви можете запустити /bin/chmod
. І /bin
монтується перед rc.local
пробіжками.
Коли запускається як корінь, /bin/chmod
рідко виходить з ладу. Він вийде з ладу, якщо файл, на якому працює, є лише для читання, і може вийти з ладу, якщо файлова система, на якій він не підтримує, не має дозволів. Ніякого ймовірного тут немає.
До речі, sh -e
це єдина причина, яка насправді була б проблемою, якщо її chmod
не вдалося. Коли ви запускаєте файл сценарію, явно викликаючи його інтерпретатора, не має значення, чи файл позначений виконуваним. Тільки якщо це сказало /script.sh
б, значення виконавчого файлу файлу має значення. Оскільки він говорить sh /script.sh
, він не робить (якщо, звичайно, не /script.sh
дзвонить сам під час його запуску, що може призвести до того, що він не може бути виконаним, але навряд чи він називає себе).
То що не вдалося?
sh /home/incero/startup_script.sh
не вдалося. Майже напевно.
Ми знаємо, що він запустився, тому що завантажив /script.sh
.
(Інакше було б важливо переконатися, що він запустився, якщо якимось чином /bin
не був у PATH - rc.local
не обов'язково такий же, PATH
як у вас, коли ви увійшли в систему. Якщо ви /bin
не були в rc.local
шляху, це потрібно sh
запустити як /bin/sh
. Так як це було запущено, /bin
є в PATH
, що означає, що ви можете запускати інші команди, які знаходяться в них /bin
, не повністю кваліфікуючи їх імена. Наприклад, ви можете запускатись просто, chmod
а не /bin/chmod
. Однак, у відповідності зі своїм стилем в rc.local
, я використовував повністю кваліфіковані імена для всіх команд, за винятком випадків sh
, коли я пропоную вам запустити їх.)
Ми можемо бути впевнені, що /bin/chmod +x /script.sh
ніколи не бігали (або ви побачите, що це /script.sh
було страчено). І ми знаємо, що також sh /script.sh
не працювали.
Але це завантажили /script.sh
. Це вдалося! Як воно могло провалитися?
Два значення успіху
Є дві різні речі, які людина може означати, коли він / він каже, що команда успішна:
- Це робило те, що ти хотів, щоб це зробили.
- Він повідомив, що це досяг успіху.
І так це за невдачу. Коли людина каже, що команда не вдалася, це може означати:
- Це не зробило те, що ви хотіли.
- Він повідомив, що це не вдалося.
Сценарій, який запускається sh -e
, як-от rc.local
, зупинить виконання першого разу, коли команда повідомить, що не вдалося . Це не має значення, що насправді зробила команда.
Якщо ви не збираєтесь startup_script.sh
повідомляти про помилку, коли вона робить те, що ви хочете, це помилка startup_script.sh
.
- Деякі помилки заважають сценарію виконувати те, що ви хочете. Вони впливають на те, що програмісти називають його побічними ефектами .
- А деякі помилки заважають скрипту правильно повідомляти про те, чи вдалося це. Вони впливають на те, що програмісти називають його поверненим значенням (що в даному випадку є статусом виходу ).
Швидше за startup_script.sh
все, він зробив усе, що повинен, окрім випадків, коли це не вдалося.
Як повідомляється про успіх чи невдачу
Сценарій - це список нульових або більше команд. Кожна команда має статус виходу. Якщо припустити, що фактично не працює сценарій (наприклад, якщо інтерпретатор не міг прочитати наступний рядок сценарію під час його запуску), статус виходу сценарію такий:
0
(успіх), якщо скрипт був порожнім (тобто не мав команд).
N
, якщо скрипт закінчився в результаті команди , де є якийсь вихідний код.exit N
N
- Код виходу останньої команди, яка запускалася в сценарії, в іншому випадку.
Коли виконується виконуваний файл, він повідомляє про власний код виходу - вони не тільки для сценаріїв. (А технічно, вихідні коди зі скриптів - це вихідні коди, повернені оболонками, які ними керують.)
Наприклад, якщо програма C закінчується exit(0);
або return 0;
за її main()
функцією, код 0
надається операційній системі, яка надає їй процес виклику (який, наприклад, може бути оболонкою, з якої запускалася програма).
0
означає, що програма вдалася. Кожне інше число означає, що воно не вдалося. (Таким чином, різні цифри іноді можуть посилатися на різні причини невдачі програми.)
Команди означають збій
Іноді ви запускаєте програму з наміром, що вона вийде з ладу. У цих ситуаціях ви можете вважати його провал як успіх, навіть якщо програма не повідомляє про помилку. Наприклад, ви можете використовувати rm
файл, який, як ви підозрюєте, вже не існує, просто переконайтесь, що його видалено.
Щось подібне, мабуть, відбувається в startup_script.sh
, перед тим, як воно перестане працювати. Останньою команди запуску в сценарії, ймовірно , повідомлення про це (навіть якщо його «провал» може бути абсолютно нормально і навіть необхідно), що робить звіт про помилку сценарію.
Тести означають збій
Один особливий вид команди - це тест , під яким я маю на увазі команду, яку виконують за її зворотним значенням, а не за її побічними ефектами. Тобто тест - це команда, яка виконується так, щоб її статус виходу можна було вивчити (і діяти).
Наприклад, припустимо, я забуваю, якщо 4 дорівнює 5. На щастя, я знаю сценарій оболонки:
if [ 4 -eq 5 ]; then
echo "Yeah, they're totally the same."
fi
Тут тест [ -eq 5 ]
не вдається, оскільки виходить 4 4 5 зрештою. Це не означає, що тест працював неправильно; це було. Завданням було перевірити, чи 4 = 5, а потім повідомити про успіх, якщо так, а провал - якщо ні.
Розумієте, в сценаріях оболонок успіх також може означати істину , а невдача також може означати хибність .
Незважаючи на те, що echo
твердження ніколи не виконується, if
блок в цілому повертає успіх.
Однак, мабуть, я написав це коротше:
[ 4 -eq 5 ] && echo "Yeah, they're totally the same."
Це звичайна стенограма. &&
є булевим і оператором. &&
Вираз, який складається з &&
з заявами з обох боків, повертає помилкове (відмова) , якщо обидві сторони не повертають істинний (успіх). Так само, як звичайний і .
Якщо хтось запитає вас, "Дерек ходив у торговий центр і думав про метелика?" і ти знаєш, що Дерек не ходив до торгового центру, не потрібно займатись з'ясуванням, чи думав він про метелика.
Аналогічно, якщо команда зліва від &&
fails (false), весь &&
вираз негайно виходить з ладу (false). Заява праворуч &&
ніколи не виконується.
Ось, [ 4 -eq 5 ]
біжить. Він "провалюється" (повертаючи помилкове). Отже весь &&
вираз провалюється. echo "Yeah, they're totally the same."
ніколи не бігає. Все поводилось так, як і належить, але ця команда повідомляє про помилку (навіть незважаючи на те, що інакше еквівалентний if
умовно вище звіт про успіх).
Якби це останнє твердження в сценарії (і сценарій дійшов до нього, а не закінчувався в якийсь момент перед ним), весь сценарій повідомив би про помилку .
Окрім цього, є ще багато тестів. Наприклад, є тести з ||
("або"). Однак, наведений вище приклад повинен бути достатнім, щоб пояснити, що таке тести, і дати можливість ефективно використовувати документацію, щоб визначити, чи є тест / команда певним тестом.
sh
vs. sh -e
, Переглянуто
Оскільки в #!
рядку (дивись також це питання ) у верхній частині /etc/rc.local
має sh -e
, операційна система запускає сценарій , як якщо б він був викликаний за допомогою команди:
sh -e /etc/rc.local
На відміну від цього , ваші інші сценарії, такі як startup_script.sh
, працювати без з -e
прапором:
sh /home/incero/startup_script.sh
Отже, вони продовжують працювати навіть тоді, коли команда в них повідомляє про помилку.
Це нормально і добре. rc.local
слід викликати sh -e
і більшість інших скриптів - включаючи більшість скриптів, якими керує - rc.local
не повинен.
Просто не забудьте запам'ятати різницю:
Сценарії запускаються з sh -e
помилкою звітування про вихід із першого разу, коли команда, яку вони містять, виходить з ладу звітування.
Схоже, що сценарій являв собою єдину довгу команду, що складається з усіх команд у скрипті, об'єднаних з &&
операторами.
Сценарії, запущені з sh
(без -e
), продовжують виконуватись до тих пір, поки вони не прийдуть до команди, яка завершує (виходить із них), або до самого кінця сценарію. Успіх або невдача кожної команди по суті не має значення (якщо тільки наступна команда не перевіряє її). Сценарій виходить зі статусом виходу останнього запуску команди.
Допомагаючи своєму сценарію зрозуміти, що це не така невдача
Як можна утримати сценарій від того, що він не вважав його невдалим, коли цього не зробив?
Ви дивитеся на те, що відбувається безпосередньо перед тим, як це буде запущено.
Якщо команда не вдалася, коли вона мала досягти успіху, з’ясуйте, чому, і виправте проблему.
Якщо команда не вдалася, і це сталося правильно, тоді запобігайте поширенню цього стану відмови.
Один із способів утримати статус відмови від розповсюдження - це запустити іншу команду, яка є успішною. /bin/true
не має побічних ефектів і повідомляє про успіх (так само, як /bin/false
нічого, а також не дає результатів).
Інша полягає в тому, щоб переконатися, що сценарій закінчується exit 0
.
Це не обов'язково те саме, що exit 0
бути в кінці сценарію. Наприклад, може бути if
-блок, де сценарій закривається всередині.
Найкраще знати, що змушує ваш сценарій повідомляти про помилку, перш ніж змусити його повідомити про успіх. Якщо це дійсно не вдається певним чином (у сенсі не робити те, що ви хочете), ви не хочете, щоб він повідомляв про успіх.
Швидке виправлення
Якщо ви не можете досягти startup_script.sh
успіху у звіті про вихід, ви можете змінити команду, rc.local
яка її виконує, так що команда повідомляє про успіх, хоча startup_script.sh
й не зробила.
На даний момент у вас є:
sh /home/incero/startup_script.sh
Ця команда має однакові побічні ефекти (тобто побічний ефект запуску startup_script.sh
), але завжди повідомляє про успіх:
sh /home/incero/startup_script.sh || /bin/true
Пам'ятайте, краще знати, чому startup_script.sh
повідомляє про помилку, і виправити це.
Як працює швидке виправлення
Це насправді приклад ||
тесту, або тесту.
Припустимо, ви запитаєте, чи я вийняв сміття чи почистив сову. Якщо я вийняв сміття, я правдиво можу сказати "так", навіть якщо я не пам'ятаю, чи я чистив сову.
Команда зліва від ||
запуску. Якщо це вдасться (правда), правий бік не повинен бігати. Тож якщо startup_script.sh
звіт про успіх, true
команда ніколи не виконується.
Однак якщо startup_script.sh
повідомлення про збій [я не вийняв сміття] , то результат /bin/true
[якщо я почистив сову] має значення.
/bin/true
завжди повертає успіх (або справжній , як ми його іноді називаємо). Отже, вся команда вдається, і наступна команда в rc.local
може запуститися.
Додаткова примітка про успіх / невдачу, правда / хибність, нуль / нуль.
Сміливо ігноруйте це. Ви можете прочитати це, якщо ви програмуєте більш ніж однією мовою (тобто, не лише сценаріями оболонок).
Це велика плутанина для скриптових оболонок, які займаються мовами програмування, такими як C, і для програмістів на C, які займаються скриптом оболонок, виявити:
У сценарії оболонок:
- Повернене значення
0
означає успіх та / або істину .
- Повернене значення чогось іншого, ніж
0
означає відмову та / або хибність .
У програмуванні на С:
- Повернене значення
0
означає хибне ..
- Повернене значення чогось іншого, ніж
0
означає правду .
- Не існує простого правила, що означає успіх, а що означає невдачу. Іноді
0
означає успіх, інший раз це означає невдачу, а інший раз означає, що сума двох доданих вами чисел дорівнює нулю. Повернені значення в загальному програмуванні використовуються для передачі різноманітної інформації різного роду.
- Чисельний статус виходу програми повинен вказувати на успіх чи невдачу відповідно до правил сценаріїв оболонок. Тобто, хоч це
0
означає, що у вашій програмі C неправдиво, ви все одно змушуєте програму повертатися 0
як її вихідний код, якщо ви хочете, щоб вона повідомила про її успіх (що оболонка потім інтерпретує як істинне ).