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:
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? 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