Vous pouvez aller jusqu'à A Quick Fix, mais ce n'est pas nécessairement la meilleure option. Je recommande donc de lire tout cela en premier.
rc.local
ne tolère pas les erreurs.
rc.local
ne fournit pas un moyen de récupérer intelligemment des erreurs. Si une commande échoue, elle cesse de s'exécuter. La première ligne, #!/bin/sh -e
provoque son exécution dans un shell appelé avec l' -e
indicateur. L' -e
indicateur est ce qui fait qu'un script (dans ce cas, rc.local
) cesse de s'exécuter la première fois qu'une commande échoue.
Vous voulez rc.local
vous comporter comme ça. Si une commande échoue, vous ne voulez pas qu'elle continue avec les autres commandes de démarrage sur lesquelles elle pourrait s'appuyer.
Donc, si une commande échoue, les commandes suivantes ne seront pas exécutées. Le problème ici est qu’il /script.sh
n’a pas été exécuté (ce n’est pas son échec, voir ci-dessous), donc probablement une commande avant son échec. Mais lequel?
Était-ce /bin/chmod +x /script.sh
?
Non.
chmod
fonctionne bien à tout moment. /bin
Vous pouvez exécuter le système de fichiers qui contient a été monté /bin/chmod
. Et /bin
est monté avant les rc.local
courses.
Lorsqu'il est exécuté en tant que root, il /bin/chmod
échoue rarement. Il échouera si le fichier sur lequel il opère est en lecture seule et risque d' échouer si le système de fichiers sur lequel il est actif ne dispose pas d'autorisations prises en charge. Ni est probable ici.
À propos, sh -e
est la seule raison pour laquelle ce serait un problème en cas d' chmod
échec. Lorsque vous exécutez un fichier de script en appelant explicitement son interpréteur, le fichier est considéré comme exécutable. Ce n'est que si cela est dit /script.sh
que le bit exécutable du fichier importera. Puisqu'elle dit sh /script.sh
, elle ne le fait pas (à moins bien sûr de /script.sh
s'appeler pendant son exécution, ce qui pourrait échouer si elle n'est pas exécutable, mais il est peu probable qu'elle s'appelle elle-même).
Alors qu'est-ce qui a échoué?
sh /home/incero/startup_script.sh
échoué. Presque certainement.
Nous savons qu'il a fonctionné, car il a été téléchargé /script.sh
.
( Dans le cas contraire, il serait important de vous assurer qu'il couriez, en cas d'une certaine manière /bin
n'a pas été dans le PATH - rc.local
n'a pas nécessairement la même PATH
. Que vous avez lorsque vous êtes connecté Si /bin
n'étaient pas dans rc.local
le chemin de », ce il faudrait sh
être exécuté comme /bin/sh
. Puisqu'il couriez, /bin
est en PATH
, ce qui signifie que vous pouvez exécuter d' autres commandes qui sont situées dans /bin
, sans qualifier pleinement leurs noms. par exemple, vous pouvez exécuter simplement chmod
plutôt que /bin/chmod
. Cependant, conformément à votre style dans rc.local
, je l' ai utilisé les noms qualifiés pour toutes les commandes , à l' exception sh
, chaque fois que je vous suggère de les exécuter.)
Nous pouvons être pratiquement sûrs de /bin/chmod +x /script.sh
ne jamais courir (ou vous verriez que cela a /script.sh
été exécuté). Et nous savons que ce sh /script.sh
n’était pas le cas non plus.
Mais c'est téléchargé /script.sh
. Ça a réussi! Comment pourrait-il échouer?
Deux sens du succès
Il y a deux choses différentes qu'une personne peut vouloir dire quand elle dit qu'une commande a réussi:
- Il a fait ce que tu voulais qu'il fasse.
- Il a rapporté qu'il a réussi.
Et c'est donc pour l'échec. Lorsqu'une personne dit qu'une commande a échoué, cela peut vouloir dire:
- Il n'a pas fait ce que tu voulais qu'il fasse.
- Il a rapporté que cela a échoué.
Un script exécuté avec sh -e
, comme rc.local
, arrêtera de courir la première fois qu'une commande rapporte son échec . Ce que la commande a réellement fait ne change rien.
Sauf si vous avez l'intention startup_script.sh
de signaler un échec lorsqu'il fait ce que vous voulez, il s'agit d'un bogue startup_script.sh
.
- Certains bogues empêchent un script de faire ce que vous voulez. Ils affectent ce que les programmeurs appellent ses effets secondaires .
- Et certains bogues empêchent un script de signaler correctement s'il a réussi ou non. Ils affectent ce que les programmeurs appellent sa valeur de retour (qui dans ce cas est un état de sortie ).
Il est fort probable que startup_script.sh
tout a été fait, sauf que cela a échoué.
Comment le succès ou l'échec est signalé
Un script est une liste de zéro ou plusieurs commandes. Chaque commande a un statut de sortie. En supposant qu’il n’existe pas d’échec lors de l’exécution réelle du script (par exemple, si l’interprète ne peut pas lire la ligne suivante du script lorsqu’il est exécuté), le statut de sortie d’un script est le suivant:
0
(succès) si le script était vide (c.-à-d. sans commandes).
N
, si le script se termine à la suite de la commande , où se trouve un code de sortie.exit N
N
- Le code de sortie de la dernière commande exécutée dans le script, sinon.
Lorsqu'un exécutable s'exécute, il indique son propre code de sortie - il ne s'agit pas uniquement de scripts. (Et techniquement, les codes de sortie des scripts sont les codes de sortie renvoyés par les shells qui les exécutent.)
Par exemple, si un programme C se termine par exit(0);
ou return 0;
dans sa main()
fonction, le code 0
est donné au système d'exploitation, qui le fournit au processus appelant (qui peut être, par exemple, le shell à partir duquel le programme a été exécuté).
0
signifie que le programme a réussi. Chaque autre numéro signifie que cela a échoué. (Ainsi, différents numéros peuvent parfois indiquer différentes raisons pour lesquelles le programme a échoué.)
Commandes vouées à l'échec
Parfois, vous exécutez un programme avec l’intention d’échouer. Dans ces situations, son échec peut être considéré comme un succès, même si le programme ne signale pas un échec. Par exemple, vous pouvez utiliser rm
un fichier dont vous pensez qu'il n'existe pas déjà, simplement pour vous assurer qu'il est supprimé.
Quelque chose comme ça se passe probablement startup_script.sh
juste avant que ça arrête de courir. La dernière commande à exécuter dans le script est probablement le signalement d'un échec (même si son "échec" peut être totalement correct, voire nécessaire), ce qui entraîne l'échec du rapport du script.
Tests voués à l'échec
Un type particulier de commande est un test , j'entends par là une commande exécutée pour sa valeur de retour plutôt que pour ses effets secondaires. C'est-à-dire qu'un test est une commande qui est exécutée afin que son statut de sortie puisse être examiné (et utilisé).
Par exemple, supposons que j'oublie si 4 est égal à 5. Heureusement, je connais les scripts shell:
if [ 4 -eq 5 ]; then
echo "Yeah, they're totally the same."
fi
Ici, le test [ -eq 5 ]
échoue car il s'avère que 4 5 après tout. Cela ne signifie pas que le test n'a pas fonctionné correctement. ça faisait. Son travail consistait à vérifier si 4 = 5, puis signaler la réussite si oui, et l'échec si non.
Vous voyez, dans les scripts shell, succès peut également signifier vrai et échec, faux .
Bien que l' echo
instruction ne soit jamais exécutée, le if
bloc dans son ensemble renvoie le succès.
Cependant, supposé que je l’ai écrit plus court:
[ 4 -eq 5 ] && echo "Yeah, they're totally the same."
C'est un raccourci courant. &&
est un booléen et un opérateur. Une &&
expression, qui consiste en des &&
déclarations de chaque côté, renvoie false (échec) à moins que les deux côtés ne renvoient true (succès). Juste comme une normale et .
Si quelqu'un vous demande, "Est-ce que Derek est allé au centre commercial et a pensé à un papillon?" et vous savez que Derek n'est pas allé au centre commercial, vous n'avez pas à vous soucier de savoir s'il pensait à un papillon.
De même, si la commande à gauche de &&
échoue (false), toute l' &&
expression échoue immédiatement (false). La déclaration à droite de &&
n'est jamais exécutée.
Ici, [ 4 -eq 5 ]
court. Cela "échoue" (retourne faux). Donc, toute l' &&
expression échoue. echo "Yeah, they're totally the same."
ne court jamais. Tout a fonctionné comme il se doit, mais cette commande signale un échec (même si la if
condition conditionnelle équivalente ci-dessus indique un succès).
S'il s'agissait de la dernière instruction d'un script (et que le script s'y trouvait, plutôt que de se terminer un peu avant), le script entier signalerait un échec .
Il y a beaucoup de tests en plus de cela. Par exemple, il existe des tests avec ||
("ou"). Cependant, l'exemple ci-dessus devrait suffire à expliquer ce que sont les tests et à vous permettre d'utiliser efficacement la documentation pour déterminer si une instruction ou une commande particulière est un test.
sh
vs sh -e
, revisité
Depuis la #!
ligne (voir aussi cette question ) en haut de /etc/rc.local
a sh -e
, le système d'exploitation exécute le script comme s'il était appelé avec la commande:
sh -e /etc/rc.local
En revanche, vos autres scripts, tels que startup_script.sh
, s'exécutent sans l' -e
indicateur:
sh /home/incero/startup_script.sh
Par conséquent, ils continuent à fonctionner même lorsqu'une commande en eux signale un échec.
C'est normal et bon. rc.local
doit être appelé avec sh -e
et la plupart des autres scripts, y compris la plupart des scripts exécutés par rc.local
--should.
Assurez-vous simplement de vous souvenir de la différence:
Les scripts s'exécutent avec un sh -e
échec de rapport de sortie la première fois qu'une commande qu'ils contiennent ferme les échecs de rapport.
C'est comme si le script était une longue commande composée de toutes les commandes du script jointes à des &&
opérateurs.
Les scripts s'exécutent avec sh
(sans -e
) continuer à s'exécuter jusqu'à ce qu'ils aboutissent à une commande qui les termine (se termine) ou à la toute fin du script. Le succès ou l'échec de chaque commande est essentiellement sans importance (à moins que la commande suivante ne le vérifie). Le script se ferme avec le statut de sortie de la dernière commande exécutée.
Aider votre script à comprendre que ce n'est pas un tel échec après tout
Comment pouvez-vous empêcher votre script de penser qu'il a échoué?
Vous regardez ce qui se passe juste avant la fin de l'exécution.
Si une commande échoue alors qu'elle aurait dû réussir, déterminez pourquoi et corrigez le problème.
Si une commande échoue et que c'est la bonne chose à faire, empêchez la propagation de cet état d'échec.
Une façon de garder un état d'échec de se propager consiste à exécuter une autre commande qui réussit. /bin/true
n'a aucun effet secondaire et signale le succès (tout comme /bin/false
rien et échoue également).
Une autre consiste à s'assurer que le script est terminé par exit 0
.
Ce n'est pas nécessairement la même chose exit 0
qu'être à la fin du script. Par exemple, il peut y avoir un if
bloc où le script se termine à l'intérieur.
Il est préférable de savoir ce qui provoque l'échec de votre script avant de lui signaler le succès. S'il échoue vraiment (en ce sens qu'il ne fait pas ce que vous voulez), vous ne voulez pas vraiment qu'il fasse état d'un succès.
Une solution rapide
Si vous ne pouvez pas assurer le startup_script.sh
succès du rapport de sortie, vous pouvez modifier la commande dans rc.local
laquelle il s'exécute, de sorte que la commande signale le succès, même si ce startup_script.sh
n'est pas le cas.
Actuellement vous avez:
sh /home/incero/startup_script.sh
Cette commande a les mêmes effets secondaires (c.-à-d. L'effet secondaire de l'exécution startup_script.sh
), mais indique toujours le succès:
sh /home/incero/startup_script.sh || /bin/true
N'oubliez pas qu'il est préférable de savoir pourquoi un startup_script.sh
échec est signalé et de le réparer.
Comment fonctionne le Quick Fix
Ceci est en fait un exemple de ||
test, un ou un test.
Supposons que vous me demandiez si j'ai sorti la poubelle ou si j'ai brossé le hibou. Si je sortais les poubelles, je pourrais sincèrement dire «oui», même si je ne me souvenais pas si j'avais brossé le hibou.
La commande à gauche de ||
run. Si cela réussit (vrai), alors le membre de droite n'a pas à courir. Donc, si le résultat est startup_script.sh
positif, la true
commande ne sera jamais exécutée.
Cependant, si un startup_script.sh
échec est signalé [je n'ai pas sorti la corbeille] , le résultat de /bin/true
[si je brosse le hibou] est important.
/bin/true
renvoie toujours le succès (ou vrai , comme nous l'appelons parfois). Par conséquent, la commande entière réussit et la commande suivante rc.local
peut être exécutée.
Une note supplémentaire sur le succès / l'échec, vrai / faux, zéro / différent de zéro.
N'hésitez pas à l'ignorer. Vous voudrez peut-être lire ceci si vous programmez dans plus d'une langue (c.-à-d., Pas seulement les scripts shell).
Il est très confus pour les scripteurs shell utilisant des langages de programmation tels que C, et pour les programmeurs C utilisant les scripts shell de découvrir:
Dans les scripts shell:
- Une valeur de retour
0
signifie succès et / ou vrai .
- Une valeur de retour autre que
0
signifiant échec et / ou faux .
Programmation en C:
- Une valeur de retour des
0
moyens faux ..
- Une valeur de retour de quelque chose d'autre que
0
signifie true .
- Il n'y a pas de règle simple pour ce qui signifie succès et ce qui signifie échec. Parfois, cela
0
signifie succès, parfois cela signifie échec, d'autres fois cela signifie que la somme des deux nombres que vous venez d'ajouter est égale à zéro. Les valeurs de retour dans la programmation générale sont utilisées pour signaler une grande variété d'informations de types différents.
- Le statut de sortie numérique d'un programme doit indiquer un succès ou un échec conformément aux règles applicables aux scripts shell. En d’autres termes , même si
0
signifie faux dans votre programme C, vous faites 0
quand même que votre programme retourne comme code de sortie si vous voulez qu’il signale qu’il a réussi (ce que le shell interprète alors comme vrai ).
incero
(je suppose que c'est le nom d'utilisateur) de toute façon , c'est un administrateur , et il est donc autorisé à exécuter n'importe quelle commande enroot
(en entrant son propre mot de passe utilisateur), ce qui n'est pas super dangereux et non dangereux . Si vous souhaitez d’autres solutions, je vous recommande de poser une nouvelle question à ce sujet . L'un des problèmes était la raison pour laquelle les commandesrc.local
ne s'exécutaient pas (et vous avez également vérifié ce qui se passerait si vous les faisiez continuer à s'exécuter). Vous avez maintenant un problème différent: vous voulez que la machine soit connectée au réseau avant l'rc.local
exécution, ou planifier l'exécutionstartup_script.sh
ultérieure./usr/bin/sudo service networking restart
au script de démarrage avant la commande wget a entraîné le fonctionnement de wget.rc.local
Vous pouvez (dans les variantes Unix que j'utilise) remplacer le comportement par défaut en modifiant:
À:
Au début du script. Le drapeau "-e" indique à sh de sortir à la première erreur. Le nom long de ce drapeau est "errexit", la ligne d'origine est donc équivalente à:
la source
-e
œuvres sur Jessie raspbian.-e
est là pour une raison. Je ne ferais pas ça si j'étais toi. Mais je ne suis pas tes parents.changer la première ligne de:
#!/bin/sh -e
à!/bin/sh -e
la source
#!
est la bonne. (Au moins, la#!
partie est correcte. Et le reste fonctionne généralement bien pour, pourrc.local
.) Voir cet article et cette question . Quoi qu'il en soit, bienvenue à Ask Ubuntu!