Почему rc.local не запускает все мои команды, и что я могу с этим поделать?

У меня есть следующий сценарий rc.local:

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

В первой строке startup_script.sh фактически загружается файл script.sh в /script.sh, указанный в третьей строке.

К сожалению, похоже, что он не делает сценарий исполняемым или не запускает сценарий. Запуск файла rc.local вручную после запуска работает отлично. Может ли chmod не запускаться при запуске или что-то в этом роде?

35
задан 14 January 2013 в 17:07

3 ответа

изменить первую строку с: #!/bin/sh -e на !/bin/sh -e

0
ответ дан 14 January 2013 в 17:07

Вы можете (в используемых мной версиях Unix) переопределить поведение по умолчанию, изменив:

#!/bin/sh -e

На:

#!/bin/sh

В начале сценария. Флаг "-e" указывает sh выйти при первой ошибке. Длинное имя этого флага «errexit», поэтому оригинальная строка эквивалентна:

#!/bin/sh --errexit
0
ответ дан 14 January 2013 в 17:07

Вы можете полностью перейти к A Quick Fix , но это не обязательно лучший вариант. Поэтому я рекомендую сначала прочитать все это.

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, это потребовало бы, чтобы sh был запущен как /bin/sh. Поскольку он выполнялся, /bin находится в PATH, что означает, что вы можете запускать другие команды, расположенные в /bin, без полной квалификации их имен. Например, вы можете запустить только chmod, а не /bin/chmod. Однако, в соответствии с вашим стилем в rc.local, я использовал полные имена для всех команд, кроме sh, всякий раз, когда я предлагаю вам их запустить.)

Мы можем быть уверены, что /bin/chmod +x /script.sh никогда не выполнялся (или вы увидит, что /script.sh был казнен). И мы знаем, что sh /script.sh тоже не бегал.

Но он скачал /script.sh. Это удалось! Как это может потерпеть неудачу?

Два значения успеха

Есть две разные вещи, которые человек может иметь в виду, когда он / она говорит, что команда выполнена успешно:

  1. Он сделал что вы хотели сделать.
  2. Он сообщил, что это удалось.

И так для неудачи. Когда человек говорит, что команда не выполнена, это может означать:

  1. Она не делает то, что вы от нее хотели.
  2. Он сообщил, что потерпел неудачу.

Скрипт, запущенный с 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."

Это обычная запись. && является логическим оператором и . Выражение &&, которое состоит из && с операторами по обе стороны, возвращает false (сбой), если обе стороны не вернут true (успех). Так же, как нормальные и .

Если кто-то спросит вас: «Дерек пошел в торговый центр и подумал о бабочке?» и вы знаете, что Дерек не ходил в торговый центр, вам не нужно выяснять, думает ли он о бабочке.

Аналогичным образом, если команда слева от && не выполняется (false), все выражение && сразу же завершается ошибкой (false). Утверждение в правой части && никогда не выполняется.

Здесь [ 4 -eq 5 ] работает. Это "не удается" (возвращая ложь). Таким образом, все выражение && не выполняется. echo "Yeah, they're totally the same." никогда не бежит. Все вело себя так, как и должно быть, но эта команда сообщает об ошибке (хотя в противном случае эквивалентное условие if выше сообщает об успехе).

Если бы это было последнее утверждение в сценарии (и сценарий дошел до него,

0
ответ дан 14 January 2013 в 17:07

Другие вопросы по тегам:

Похожие вопросы: