J'ai un court script qui est exécuté par un démon système pour des événements particuliers. Je sais que l'événement se produit et que le script est en cours d'exécution, mais il ne fait pas ce que je souhaite. Étrangement, il le fait lorsque je l'exécute manuellement, donc je suis très confus.
Comment savoir ce qui se passe? Le script est essentiellement une série de commandes comme celle-ci:
/bin/foo on 3
sudo bar a
U&L
. J'ai mal lu le titre et suggérerais que "Consigner la sortie d'un script système pour le débogage" rendrait le but plus clair. De plus, mon cerveau se fige lorsque je lis cesfoo
bar
exemples, je préfère quelque chose qui ressemble plus au monde réel. Je suis réticent à modifier un article, alors je vous laisse le soin de penser que cela peut être amélioré.Réponses:
Tout d'abord, si le script est exécuté par un démon système et que ce démon s'exécute avec les privilèges root, vous n'avez pas besoin de l'utiliser
sudo
. Cela inclutinit
(etsystemd
), ce qui inclutrc.local
. Si ce démon ne s'exécute pas avec les privilèges root, ilsudo
ne fonctionnera pas à moins qu'il ne/etc/sudoers
soit configuré pour autoriser cela (et sans mot de passe). Les utilisateurs de Raspbian peuvent être déroutés par cela car l'pi
utilisateur est autorisé à faire quoi que ce soit par défaut (et si vous regardez dedans,/etc/sudoers
vous verrez comment cela est accompli).Ensuite, vous pouvez capturer la sortie de n'importe quel
bash
script, ou de tout ensemble de commandes à l'intérieur d'un script bash, en les exécutant dans un sous-shell comme ceci: 1Le
()
indique un sous-shell . Toutes les sorties de tout ce qui se trouve à l'intérieur sont redirigées vers un/var/log/myTestLog.txt
fichier. Quelques notes:&>
est un bashisme , donc si le script est exécuté via un shebang sur la première ligne, il devrait l'être#!/bin/bash
, pas seulement/bin/sh
. Les «bashismes» ne fonctionnent que dans labash
coquille.Cela inclut
/etc/rc.local
, qui par défaut utilise/bin/sh
(c'est-à-dire, oui, vous pouvez le changer en toute sécurité/bin/bash
)./var/log
nécessite des privilèges root pour écrire. Si le processus n'en a pas, utilisez ou créez un répertoire que vous savez qu'il peut. En cas de doute, si vous pouvez tester cela sans avoir à arrêter ou redémarrer le système, utilisez/tmp
, qui est accessible en écriture (c'est-à-dire par n'importe qui). Cependant,/tmp
ne persiste pas entre les bottes. Il s'agit également d'une petite partition basée sur la RAM, donc n'y écrivez pas de données. Ce n'est pas votre carte SD [en fait sur les versions actuelles de Raspbian, mais ne comptez pas sur cela dans la pratique] .&>
remplacera quoi que ce soitmyTestLog.txt
. Si vous souhaitez ajouter à un journal existant, ce qui peut être une bonne idée à des fins de débogage, utilisez&>>
. Vous pouvez ensuite ajouter une commande au début de ce sous-shell comme ceci:Pour séparer les informations de chaque exécution. Si vous n'êtes pas sûr de ce que cela fait, essayez sur la ligne de commande.
Ce dernier point est une bonne illustration de quelque chose que vous pouvez faire en ce qui concerne les commandes qui ne produisent rien - mais la plupart le font si vous incluez, par exemple,
-v
pour "verbeux". Attention à certaines commandes-v
signifie "imprimer les informations de version". Jetez un œil dans la page de manuel de la commande pour être sûr si et comment cela fonctionnera (certaines commandes utilisent également un commutateur différent de-v
).Par convention, les commandes renvoient également une valeur de 0 une fois terminées. Ceci est parfois appelé le "statut de sortie" et vous ne le voyez pas normalement, mais le shell vous le montrera
echo $?
. EssayerVous obtiendrez 0 et 2. Si vous recherchez ensuite dans la page de manuel
ls
sous "État de sortie", vous verrez le cryptique plutôt non spécifique:Ce qui peut ou non être mieux que rien, mais voilà.
À tout le moins, cela indique que la commande a échoué pour une raison quelconque. Le statut de sortie vous permet également de faire des choses comme ceci:
Dans
&&
ce cas, le signifie "si la première commande réussit", en supposant que la première commande utilise la convention de retour de 0 (c'est pourquoi ils le font généralement). Si/bin/foo
cela ne fonctionne pas, est introuvable, etc.,sudo bar
cela ne se produira jamais.L'utilisation d'une combinaison de messages de journalisation et d'exécution conditionnelle (
&&
) devrait vous permettre de comprendre le problème beaucoup plus près, ou au moins d'obtenir des informations qui pourraient être utiles à d'autres pour vous aider à résoudre le problème. Sans cela, le plus que quiconque puisse faire est de deviner.1. Vous pouvez effectuer la même redirection de sortie pour un script entier de l'intérieur en utilisant:
En haut (ou n'importe où, et cela s'appliquera à tout ce qui suit).
la source
Un aspect important que les gens ont tendance à oublier lors de l'exécution de scripts en tant que démons est l'environnement shell, et
$PATH
variable en particulier. Dans votre exemple, la deuxième ligne repose sur$PATH
: le nom complet desudo
is/usr/bin/sudo
, et votre shell utilisateur ne le sait que parce qu'il lui a été demandé de rechercher/usr/bin
lors de la recherche d'exécutables. Il en va de même pourbar
.Étant donné que cela
sudo
n'est pas nécessaire lors de l'exécution de scripts en tant que démons, votre deuxième ligne devrait ressembler à:la source