¿Cómo puedo usar bash's si pruebo y encuentro commands juntos?

Tengo un directory con loggings de locking, y me gustaría utilizar una statement condicional en un script bash basado en un command de búsqueda.

Los files de logging se almacenan en este formatting:

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

Quiero que la statement if solo devuelva verdadero si hay un logging de locking para una aplicación específica que se ha modificado en los últimos 5 minutos. El command de find que usaría es:

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

No estoy seguro de cómo incorporar eso en una statement if correctamente. Creo que esto podría funcionar:

 if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then service myapp restart fi 

Hay algunas áreas donde no estoy claro:

  • Miré las banderas if, pero no estoy seguro de cuál, si es que hay alguna, debería usar.
  • ¿Necesito la directiva de test o debo procesar directamente los resultados del command find o quizás usar find... | wc -l find... | wc -l para get un conteo de líneas en su lugar?
  • No es 100% necesario para responder esta pregunta, pero la test es para probar contra los códigos de retorno que devuelven los commands. Y son algo así como invisibles: ¿fuera de stdout / stderr ? Leí la página man , pero todavía no tengo muy claro cuándo usar la test y cómo depurarla.

[ y la test son sinónimos (excepto [ requiere ] ), por lo que no desea usar [ test :

 [ -x /bin/cat ] && echo 'cat is executable' test -x /bin/cat && echo 'cat is executable' 

test devuelve un estado de salida cero si la condición es verdadera, de lo contrario es distinta de cero. Esto realmente puede ser reemplazado por cualquier progtwig para verificar su estado de salida, donde 0 indica éxito y no cero indica falla:

 # 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 

Sin embargo, todos los ejemplos anteriores solo testingn contra el estado de salida del progtwig e ignoran la salida del progtwig.

Para find , deberá probar si se generó alguna salida. -n testing para una cadena no vacía:

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

Una list completa de arguments de testing está disponible invocando la help test en la command-line de bash .

Si usa bash (y no sh ), puede usar [[ condition ]] , que se comporta de manera más pnetworkingecible cuando hay espacios u otros casos especiales en su condición. De lo contrario, generalmente es lo mismo que usar [ condition ] . He usado [[ condition ]] en este ejemplo, como hago siempre que sea posible.

También cambié `command` a $(command) , que generalmente también se comporta de manera similar, pero es más agradable con los commands nesteds.

find saldrá exitosamente si no hubo ningún error, por lo que no puede contar con su estado de salida para saber si encontró algún file. Pero, como dijiste, puedes contar cuántos files encontró y probar ese número.

Sería algo como esto:

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

test (aka [ ) no comtesting los códigos de error de los commands, tiene una syntax especial para hacer testings, y luego sale con un código de error de 0 si la testing fue exitosa, o 1 en caso contrario. Es if el que verifica el código de error del command que le pasa y ejecuta su cuerpo en function del mismo.

Consulte la man test (o la help test , si usa bash ) y la help if (ídem).

En este caso, wc -l arrojará un número. Usamos la opción test -gt para probar si ese número es mayor que 0 . Si es así, test (o [ ) volverá con el código de salida 0 . if interpretará ese código de salida como exitoso, y ejecutará el código dentro de su cuerpo.

Esto sería

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

o

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

Los commands de test y [ … ] son exactamente sinónimos. La única diferencia es su nombre, y el hecho de que [ requiere un cierre ] como último argumento. Como siempre, utilice comillas dobles alnetworkingedor de la sustitución del command, de lo contrario la salida del command find se dividirá en palabras, y aquí obtendrá un error de syntax si hay más de un file coincidente (y cuando no hay arguments, [ -n ] es verdadero, mientras que usted quiere [ -n "" ] que es falso).

En ksh, bash y zsh pero no en cenizas, también puede usar [[ … ]] que tiene diferentes reglas de análisis: [ es un command común, mientras que [[ … ]] es una construcción de análisis diferente. No necesita comillas dobles dentro de [[ … ]] (aunque no duelen). Aún necesitas el ; después del command.

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

Esto puede ser potencialmente ineficiente: si hay muchos files en /var/log/crashes , find los explorará todos. Debes hacer que find se detenga tan pronto como encuentre una coincidencia, o poco después. Con GNU find (Linux no incorporado, Cygwin), use la -quit primary.

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

Con otros sistemas, la tubería se find en la head para al less salir poco después de la primera coincidencia (el hallazgo morirá por una tubería rota).

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

(Puede usar head -c 1 si su command head admite).


Alternativamente, use zsh.

 crash_files=(/var/log/crashes/**/app-*.log(mm-5[1])) if (($#crash_files)); then 

Esto debería funcionar

 if find /var/log/crashes -name 'app-\*\.log' -mmin -5 | read then service myapp restart fi