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 de plantage pour une application spécifique qui a été modifiée au cours des 5 dernières minutes. La commande find
que j'utiliserais serait:
find /var/log/crashes -name app-\*\.log -mmin -5
Je ne sais pas comment l'incorporer correctement dans une instruction if
. 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:
test
ou dois-je simplement traiter directement les résultats de la commande find, ou peut-être utiliser find... | wc -l
pour obtenir un nombre de lignes à la place?test
est pour tester par rapport aux codes de retour que les commandes retournent? Et ils sont en quelque sorte invisibles - en dehors de stdout
/stderr
? J'ai lu la page man
mais je ne sais toujours pas quand utiliser test
et comment le déboguer.[
Et test
sont des synonymes (sauf que [
Nécessite ]
), Donc vous ne voulez pas utiliser [ test
:
[ -x /bin/cat ] && echo 'cat is executable'
test -x /bin/cat && echo 'cat is executable'
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:
# echoes "command succeeded" because echo rarely fails
if /bin/echo hi; then echo 'command succeeded'; else echo 'command failed'; fi
# echoes "command failed" because rmdir requires an argument
if /bin/rmdir; then echo 'command succeeded'; else echo 'command failed'; fi
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:
if [[ -n $(find /var/log/crashes -name "app-*.log" -mmin -5) ]]
then
service myapp restart
fi
Une liste complète des arguments de test est disponible en appelant help test
À la ligne de commande bash
.
Si vous utilisez bash
(et non sh
), 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, cela revient généralement à utiliser [ condition ]
. J'ai utilisé [[ condition ]]
Dans cet exemple, comme je le fais chaque fois que possible.
J'ai également changé `command`
En $(command)
, qui se comporte généralement de la même manière, mais est plus agréable avec les commandes imbriquées.
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:
if [ $(find /var/log/crashes -name 'app-*.log' -mmin -5 | wc -l) -gt 0 ]; then
...
fi
test
(alias [
) 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'est if
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
(ou help test
, si vous utilisez bash
) et help if
(idem).
Dans ce cas, wc -l
affichera un nombre. Nous utilisons l'option de test
-gt
pour tester si ce nombre est supérieur à 0
. Si c'est le cas, test
(ou [
) retournera avec le code de sortie 0
. if
interprétera ce code de sortie comme un succès et exécutera le code dans son corps.
Ce serait
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)" ]; then
ou
if test -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)"; then
Les commandes test
et [ … ]
sont exactement synonymes. La seule différence est leur nom et le fait que [
nécessite une fermeture ]
comme dernier argument. Comme toujours, utilisez des guillemets doubles autour de la substitution de commande, sinon la sortie de la commande find
sera divisée en mots, et ici vous obtiendrez une erreur de syntaxe s'il y a plus d'un fichier correspondant (et quand il y a n'y a pas d'arguments, [ -n ]
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, tandis que [[ … ]]
est une construction d'analyse différente. Vous n'avez pas besoin de guillemets doubles à l'intérieur de [[ … ]]
(bien qu'ils ne fassent pas de mal). Vous avez toujours besoin du ;
après la commande.
if [[ -n $(find /var/log/crashes -name app-\*\.log -mmin -5) ]]; then
Cela peut être potentiellement inefficace: s'il y a beaucoup de fichiers dans /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 intégré, Cygwin), utilisez le -quit
primaire.
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print -quit)" ]; then
Avec d'autres systèmes, canalisez find
dans head
pour au moins quitter peu après la première correspondance (find mourra d'un tube cassé).
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print | head -n 1)" ]; then
(Vous pouvez utiliser head -c 1
si votre commande head
le prend en charge.)
Vous pouvez également utiliser zsh.
crash_files=(/var/log/crashes/**/app-*.log(mm-5[1]))
if (($#crash_files)); then
Cela devrait fonctionner
if find /var/log/crashes -name 'app-\*\.log' -mmin -5 | read
then
service myapp restart
fi
find /var/log/crashes -name app-\*\.log -mmin -5 -exec service myapp restart ';' -quit
est une solution appropriée ici.
-exec service myapp restart ';'
fait que find
appelle 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 fermeture de find
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.