Comment puis-je utiliser bash si tester et find des commands set?

J'ai un directory avec des journaux de crash, et j'aimerais utiliser une instruction conditionnelle dans un script bash basé sur une command find.

Les files journaux sont stockés dans ce format:

/var/log/crashes/app-2012-08-28.log /var/log/crashes/otherapp-2012-08-28.log 

Je veux que l'instruction if renvoie true uniquement s'il y a un journal de crash pour une application spécifique qui a été modifiée au cours des 5 dernières minutes. La command find que j'utiliserais est la suivante:

 find /var/log/crashes -name app-\*\.log -mmin -5 

Je ne suis pas sûr de savoir comment incorporer cela dans une déclaration if correctement. 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 si, mais je ne sais pas lequel, le cas échéant, que je devrais utiliser.
  • Ai-je besoin de la directive de test ou dois-je simplement traiter les résultats de la command find, ou peut-être utiliser find... | wc -l find... | wc -l pour get un nombre de lignes à la place?
  • Pas 100% nécessaire pour répondre à cette question, mais le test est pour tester contre les codes de return que les commands returnnent? Et ils sont en quelque sorte invisible – en dehors de stdout / stderr ? J'ai lu la page de manuel, mais je ne sais toujours pas quand utiliser le test et comment le déboguer.

[ et test sont des synonymes (sauf [ 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 non nul. 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-zéro 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 le statut 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 string non vide:

 if [[ -n $(find /var/log/crashes -name "app-*.log" -mmin -5) ]] then service myapp restart fi 

Une list complète des arguments de test est disponible en appelant le help test sur la command line 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 c'est possible.

J'ai aussi changé `command` en $(command) , qui se comporte généralement de la même façon, mais qui est plus agréable avec les commands nestedes.

find terminera avec succès s'il n'y a pas d'erreurs, vous ne pouvez donc pas countr sur son statut de sortie pour savoir s'il a trouvé un file. Mais, comme vous l'avez dit, vous pouvez countr le nombre de files trouvés et tester ce nombre.

Ce serait quelque chose comme ça:

 if [ $(find /var/log/crashes -name 'app-*.log' -mmin -5 | wc -l) -gt 0 ]; then ... fi 

test (aka [ ) ne vérifie pas les codes d'erreur des commands, il a une syntaxe spéciale pour faire des tests, puis se termine avec un code d'erreur de 0 si le test a réussi, ou 1 sinon. C'est celui qui vérifie le code d'erreur de la command que vous lui transmettez 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 test -gt pour tester si ce nombre est supérieur à 0 . Si c'est le cas, test (ou [ ) returnnera avec le code de sortie 0 . if interprétera ce code de sortie comme un succès, et il exécutera le code à l'intérieur de 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 commands test et [ … ] sont exactement synonymes. La seule différence est leur nom, et le fait que [ nécessite une clôture ] comme dernier argument. Comme toujours, utilisez des guillemets doubles autour de la substitution de la command, sinon la sortie de la command find sera fractionnée en mots et vous obtiendrez ici une erreur de syntaxe s'il y a plus d'un file correspondant (et s'il n'y a pas d'arguments, [ -n ] est vrai, alors que vous voulez [ -n "" ] qui est faux).

En ksh, bash et zsh mais pas en cendre, vous pouvez aussi utiliser [[ … ]] qui a des règles d'parsing différentes: [ est une command ordinaire, alors que [[ … ]] est une construction d'parsing différente. Vous n'avez pas besoin de guillemets doubles à l'intérieur de [[ … ]] (même s'ils ne font pas mal). Vous avez toujours besoin de la ; après la command.

 if [[ -n $(find /var/log/crashes -name app-\*\.log -mmin -5) ]]; then 

Cela peut potentiellement être inefficace: s'il y a beaucoup de files dans /var/log/crashes , find les explorera tous. Vous devriez faire en sorte que find s'arrête dès qu'il trouve un match, ou peu de time après. Avec GNU find (Linux non embarqué, Cygwin), utilisez le primaire -quit .

 if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print -quit)" ]; then 

Avec d'autres systèmes, les tuyaux se find dans la head pour au less cesser de fumer peu de time après la première allumette (la trouvaille mourra d'un tuyau 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 command head le supporte.)


Sinon, utilisez 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