Tengo un directorio con registros de bloqueo, y me gustaría usar una declaración condicional en un script bash basado en un comando de búsqueda.
Los archivos de registro se almacenan en este formato:
/var/log/crashes/app-2012-08-28.log
/var/log/crashes/otherapp-2012-08-28.log
Quiero que la declaración if solo devuelva verdadero si hay un registro de bloqueo para una aplicación específica que se ha modificado en los últimos 5 minutos. El findcomando que usaría es:
find /var/log/crashes -name app-\*\.log -mmin -5
No estoy seguro de cómo incorporar eso en una ifdeclaración 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:
- He mirado las banderas if pero no estoy seguro de cuál, si es que hay alguna, debería usar.
- ¿Necesito la
testdirectiva o debería simplemente procesar directamente los resultados del comando find, o tal vez usarfind... | wc -lpara obtener un recuento de líneas? - No es 100% necesario para responder esta pregunta, pero ¿
testes para probar los códigos de retorno que los comandos devuelven? Y son algo invisibles, fuera destdout/stderr? Leí lamanpágina, pero aún no tengo muy claro cuándo usarlatesty cómo depurarla.

find ... -exec. Vea también los comandos de ejemplo en ¿Por qué es un bucle sobre la salida de find una mala práctica?... -exec command ';' -quit, pero no creo que haya otra solución para el segundo que no sea analizar el resultado. Además, en cualquier caso, el problema principal con el análisis del resultado defind(es decir, la incapacidad para distinguir los delimitadores de los caracteres en los nombres de archivo) no se aplica, ya que no necesita encontrar delimitadores en estos casos.Respuestas:
[ytestson sinónimos (excepto que se[requieren]), por lo que no desea usar[ test:testdevuelve un estado de salida cero si la condición es verdadera, de lo contrario no es cero. En realidad, esto puede ser reemplazado por cualquier programa para verificar su estado de salida, donde 0 indica éxito y no cero indica falla:Sin embargo, todos los ejemplos anteriores solo prueban el estado de salida del programa e ignoran la salida del programa.
Para
find, deberá probar si se generó alguna salida.-nprueba para una cadena no vacía:Una lista completa de argumentos de prueba está disponible invocando
help testen labashlínea de comandos.Si está usando
bash(y nosh), puede usar[[ condition ]], lo que se comporta de manera más predecible cuando hay espacios u otros casos especiales en su condición. De lo contrario, generalmente es lo mismo que usar[ condition ]. Lo he usado[[ condition ]]en este ejemplo, como lo 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 comandos anidados.fuente
echopuede fallar: intenteecho 'oops' > /dev/full.findsaldrá con éxito si no hubo ningún error, por lo que no puede contar con su estado de salida para saber si encontró algún archivo. Pero, como dijiste, puedes contar cuántos archivos encontró y probar ese número.Sería algo como esto:
test(aka[) no verifica los códigos de error de los comandos, tiene una sintaxis especial para hacer pruebas y luego sale con un código de error de 0 si la prueba fue exitosa, o 1 en caso contrario. Esifel que comprueba el código de error del comando que le pasa y ejecuta su cuerpo en función de él.Ver
man test(ohelp test, si lo usabash) yhelp if(ídem).En este caso,
wc -lgenerará un número. Usamostestla opción-gtpara probar si ese número es mayor que0. Si es así,test(o[) volverá con el código de salida0.ifinterpretará ese código de salida como exitoso, y ejecutará el código dentro de su cuerpo.fuente
Esto sería
o
Los comandos
testy[ … ]son exactamente sinónimos. La única diferencia es su nombre y el hecho de que[requiere un cierre]como último argumento. Como siempre, use comillas dobles alrededor de la sustitución del comando, de lo contrario, la salida delfindcomando se dividirá en palabras, y aquí obtendrá un error de sintaxis si hay más de un archivo coincidente (y cuando no hay argumentos,[ -n ]es cierto , mientras que quieres[ -n "" ]que es falso).En ksh, bash y zsh pero no en ash, también puede usar
[[ … ]]que tiene diferentes reglas de análisis:[es un comando ordinario, mientras que[[ … ]]es una construcción de análisis diferente. No necesita comillas dobles en el interior[[ … ]](aunque no duelen). Todavía necesitas el;después del comando.Esto puede ser potencialmente ineficiente: si hay muchos archivos
/var/log/crashes, find los explorará a todos. Debes hacer que stop se encuentre tan pronto como encuentre una coincidencia, o poco después. Con GNU find (Linux no incrustado, Cygwin), use el-quitprimario.Con otros sistemas, tubo
findenhead, al menos, dejar de fumar poco después del primer partido (Encontrar morirá de una tubería rota).(Puedes usar
head -c 1si suheadcomando lo admite).Alternativamente, use zsh.
fuente
Esto debería funcionar
fuente
Es una solución apropiada aquí.
-exec service myapp restart ';'causasfindque invoque el comando que desea ejecutar directamente, en lugar de necesitar que el shell interprete algo.-quithacefindque salga después de procesar el comando, evitando así que el comando se ejecute nuevamente si hay varios archivos que coinciden con los criterios.fuente