Вы можете полностью перейти к Быструю настройку, но это не обязательно лучший вариант. Поэтому я рекомендую сначала прочитать все это.
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
запуском.
При запуске от имени root /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
«s путь, это потребовалось 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-5. Это не значит, что тест не был выполнен правильно; это сделал. Его работа состояла в том, чтобы проверить, если 4 = 5, затем сообщить об успехе, если так, и об ошибке, если нет.
Видите ли, в сценариях оболочки успех также может означать истину , а неудача также может означать ложь .
Хотя echo
оператор никогда не выполняется, if
блок в целом возвращает успех.
Тем не менее, предположил, что я написал это короче:
[ 4 -eq 5 ] && echo "Yeah, they're totally the same."
Это обычная стенография. &&
является логическим и оператором. &&
Выражение, которое состоит из &&
с заявлениями по обе стороны, возвращает ложное (отказ) , если обе стороны не возвращают истинный (успех). Так же , как нормальный и .
Если кто-то спросит вас: «Дерек пошел в торговый центр и подумал о бабочке?» и вы знаете, что Дерек не ходил в торговый центр, вам не нужно беспокоиться, если он подумает о бабочке.
Точно так же, если команда слева от &&
сбоев (ложь), все &&
выражение немедленно терпит неудачу (ложь). Утверждение на правой стороне &&
никогда не запускается.
Здесь [ 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
сообщает об ошибке, и исправить это.
Как работает Quick Fix
На самом деле это пример ||
теста, или теста.
Предположим, вы спросили, вынул ли я мусор или почистил сову. Если я вытащил мусор, я могу честно сказать «да», даже если я не помню, чистил ли я сову или нет.
Команда слева от ||
трасс. Если это удастся (правда), то правая сторона не должна бежать. Так что, если startup_script.sh
сообщает об успехе, true
команда никогда не запускается.
Однако, если startup_script.sh
сообщается о неудаче [я не вывез мусор] , то результат /bin/true
[если я почистил сову] имеет значение.
/bin/true
всегда возвращает успех (или истина , как мы иногда называем это). Следовательно, вся команда выполнена успешно, и rc.local
может быть выполнена следующая команда .
Дополнительное примечание об успехе / неудаче, истина / ложь, ноль / ненулевое значение.
Не стесняйтесь игнорировать это. Возможно, вы захотите прочитать это, если вы программируете на более чем одном языке (то есть, не только в сценариях оболочки).
Для создателей сценариев оболочки, использующих такие языки программирования, как C, и для программистов на C, занимающихся сценариями оболочки, возникает большая путаница:
В сценариях оболочки:
- Возвращаемое значение
0
означает успех и / или истину .
- Возвращаемое значение чего-то другого, кроме
0
означает сбой и / или false .
В программировании на С:
- Возвращаемое значение
0
означает ложь .
- Ответное значение чего - то другого , чем
0
средства истинных .
- Не существует простого правила, что означает успех, а что - неудача. Иногда
0
означает успех, иногда означает неудачу, иногда это означает, что сумма двух чисел, которые вы только что добавили, равна нулю. Возвращаемые значения в общем программировании используются, чтобы сигнализировать широкий спектр различных видов информации.
- Числовой статус завершения программы должен указывать на успех или неудачу в соответствии с правилами для сценариев оболочки. То есть, даже если
0
в вашей C-программе это означает «false», вы все равно заставите свою программу возвращаться в 0
качестве кода завершения, если вы хотите, чтобы она сообщала об успешном выполнении (которое оболочка затем интерпретирует как true ).
incero
(я предполагаю, что это имя пользователя) , в любом случае , администратор , и поэтому ему разрешено запускать любую команду какroot
(путем ввода собственного пароля пользователя), что не является небезопасным и ужасным . Если вам нужны другие решения, я рекомендую опубликовать новый вопрос по этому поводу . Одна проблема заключалась в том, что командыrc.local
не запускались (и вы также проверили, что произойдет, если вы заставите их продолжать работать). Теперь у вас другая проблема: вы хотите подключить машину к сети передrc.local
запуском или запланировать запуск наstartup_script.sh
потом./usr/bin/sudo service networking restart
к сценарию запуска до команды wget привело к тому, что wget заработал.rc.local
Вы можете (в используемых Unix-вариантах) переопределить поведение по умолчанию, изменив:
Для того, чтобы:
В начале сценария. Флаг "-e" указывает sh выйти при первой ошибке. Длинное имя этого флага "errexit", поэтому оригинальная строка эквивалентна:
источник
-e
работы на распби Джесси.-e
есть по причине. Я бы не стал этого делать на твоем месте. Но я не твои родители.изменить первую строку с:
#!/bin/sh -e
на!/bin/sh -e
источник
#!
является правильным. (По крайней мере,#!
часть правильная. А остальное, как правило, хорошо подходит дляrc.local
.) См. Эту статью и этот вопрос . В любом случае, добро пожаловать в Ask Ubuntu!