J'ai un répertoire avec des journaux de plantage et j'aimerais utiliser une instruction conditionnelle dans un script bash basé sur une commande find.
Les fichiers journaux sont stockés dans ce format:
/var/log/crashes/app-2012-08-28.log
/var/log/crashes/otherapp-2012-08-28.log
Je souhaite que l'instruction if ne renvoie true que s'il existe un journal des plantages pour une application spécifique qui a été modifiée au cours des 5 dernières minutes. La find
commande que j'utiliserais est:
find /var/log/crashes -name app-\*\.log -mmin -5
Je ne sais pas comment intégrer cela if
correctement dans une déclaration. Je pense que cela pourrait fonctionner:
if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then
service myapp restart
fi
Il y a quelques domaines où je ne suis pas clair:
- J'ai regardé les drapeaux if mais je ne sais pas lequel, le cas échéant, je devrais utiliser.
- Ai-je besoin de la
test
directive ou dois-je simplement traiter les résultats de la commande find directement, ou peut-être utiliserfind... | wc -l
pour obtenir un nombre de lignes à la place? - Pas 100% nécessaire pour répondre à cette question, mais
test
est-ce pour tester les codes de retour que les commandes retournent? Et ils sont en quelque sorte invisibles - en dehors destdout
/stderr
? J'ai lu laman
page mais je ne sais toujours pas quand l'utilisertest
et comment la déboguer.
find ... -exec
. Voir également les exemples de commandes sous Pourquoi le bouclage sur la sortie de find est-il une mauvaise pratique?... -exec command ';' -quit
, mais je ne crois pas qu'il existe de solution pour le second autre que l'analyse du résultat. De plus, dans les deux cas, le principal problème avec l'analyse du résultatfind
(c'est-à-dire l'incapacité à distinguer les délimiteurs des caractères dans les noms de fichiers) ne s'applique pas, car vous n'avez pas besoin de trouver de délimiteurs dans ces cas.Réponses:
[
ettest
sont des synonymes (sauf[
requis]
), donc vous ne voulez pas utiliser[ test
:test
renvoie un état de sortie nul si la condition est vraie, sinon différente de zéro. Cela peut en fait être remplacé par n'importe quel programme pour vérifier son état de sortie, où 0 indique le succès et non nul indique l'échec:Cependant, tous les exemples ci-dessus ne testent que l'état de sortie du programme et ignorent la sortie du programme.
Pour
find
, vous devrez tester si une sortie a été générée.-n
teste une chaîne non vide:Une liste complète des arguments de test est disponible en appelant
help test
sur labash
ligne de commande.Si vous utilisez
bash
(et nonsh
), vous pouvez utiliser[[ condition ]]
, qui se comporte de manière plus prévisible lorsqu'il y a des espaces ou d'autres cas spéciaux dans votre condition. Sinon, c'est généralement la même chose que l'utilisation[ condition ]
. J'ai utilisé[[ condition ]]
dans cet exemple, comme je le fais chaque fois que possible.J'ai également changé
`command`
pour$(command)
, qui se comporte généralement de manière similaire, mais est plus agréable avec les commandes imbriquées.la source
echo
peut échouer: essayezecho 'oops' > /dev/full
.find
se fermera correctement s'il n'y a pas eu d'erreurs, vous ne pouvez donc pas compter sur son état de sortie pour savoir s'il a trouvé un fichier. Mais, comme vous l'avez dit, vous pouvez compter le nombre de fichiers trouvés et tester ce nombre.Ce serait quelque chose comme ceci:
test
(aka[
) ne vérifie pas les codes d'erreur des commandes, il a une syntaxe spéciale pour effectuer des tests, puis se termine avec un code d'erreur de 0 si le test a réussi, ou 1 sinon. C'estif
celui qui vérifie le code d'erreur de la commande que vous lui passez et exécute son corps en fonction de celui-ci.Voir
man test
(ouhelp test
, si vous utilisezbash
), ethelp if
(idem).Dans ce cas,
wc -l
affichera un nombre. Nous utilisonstest
l'option de-gt
pour tester si ce nombre est supérieur à0
. Si c'est le cas,test
(ou[
) retournera avec le code de sortie0
.if
interprétera ce code de sortie comme un succès et exécutera le code dans son corps.la source
Ce serait
ou
Les commandes
test
et[ … ]
sont également synonymes. La seule différence est leur nom, et le fait qu'il[
nécessite une fermeture]
comme dernier argument. Comme toujours, utilisez des guillemets doubles autour de la substitution de commande, sinon la sortie de lafind
commande sera divisée en mots, et ici vous obtiendrez une erreur de syntaxe s'il y a plus d'un fichier correspondant (et lorsqu'il n'y a pas d'arguments,[ -n ]
c'est vrai , alors que vous voulez[ -n "" ]
ce qui est faux).Dans ksh, bash et zsh mais pas dans ash, vous pouvez également utiliser
[[ … ]]
qui a des règles d'analyse différentes:[
est une commande ordinaire, alors que[[ … ]]
c'est une construction d'analyse différente. Vous n'avez pas besoin de guillemets doubles à l'intérieur[[ … ]]
(bien qu'ils ne fassent pas de mal). Vous avez toujours besoin de la;
suite de la commande.Cela peut être potentiellement inefficace: s'il y a beaucoup de fichiers
/var/log/crashes
, find les explorera tous. Vous devez arrêter la recherche dès qu'elle trouve une correspondance ou peu de temps après. Avec GNU find (Linux non embarqué, Cygwin), utilisez le-quit
primaire.Avec d' autres systèmes, des tuyaux
find
danshead
au moins quitter peu après le premier match (FIND va mourir d'un tuyau cassé).(Vous pouvez utiliser
head -c 1
si votrehead
commande le prend en charge.)Vous pouvez également utiliser zsh.
la source
Cela devrait fonctionner
la source
est une solution appropriée ici.
-exec service myapp restart ';'
faitfind
invoquer la commande que vous souhaitez exécuter directement, plutôt que d'avoir besoin du shell pour interpréter quoi que ce soit.-quit
provoque la fermeturefind
après le traitement de la commande, empêchant ainsi la commande d'être exécutée à nouveau s'il se trouve que plusieurs fichiers correspondent aux critères.la source