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 find
comando que usaría es:
find /var/log/crashes -name app-\*\.log -mmin -5
No estoy seguro de cómo incorporar eso en una if
declaració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
test
directiva o debería simplemente procesar directamente los resultados del comando find, o tal vez usarfind... | wc -l
para obtener un recuento de líneas? - No es 100% necesario para responder esta pregunta, pero ¿
test
es para probar los códigos de retorno que los comandos devuelven? Y son algo invisibles, fuera destdout
/stderr
? Leí laman
página, pero aún no tengo muy claro cuándo usarlatest
y 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:
[
ytest
son sinónimos (excepto que se[
requieren]
), por lo que no desea usar[ test
:test
devuelve 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.-n
prueba para una cadena no vacía:Una lista completa de argumentos de prueba está disponible invocando
help test
en labash
lí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
echo
puede fallar: intenteecho 'oops' > /dev/full
.find
saldrá 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. Esif
el 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 -l
generará un número. Usamostest
la opción-gt
para probar si ese número es mayor que0
. Si es así,test
(o[
) volverá con el código de salida0
.if
interpretará ese código de salida como exitoso, y ejecutará el código dentro de su cuerpo.fuente
Esto sería
o
Los comandos
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, use comillas dobles alrededor de la sustitución del comando, de lo contrario, la salida delfind
comando 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-quit
primario.Con otros sistemas, tubo
find
enhead
, al menos, dejar de fumar poco después del primer partido (Encontrar morirá de una tubería rota).(Puedes usar
head -c 1
si suhead
comando lo admite).Alternativamente, use zsh.
fuente
Esto debería funcionar
fuente
Es una solución apropiada aquí.
-exec service myapp restart ';'
causasfind
que invoque el comando que desea ejecutar directamente, en lugar de necesitar que el shell interprete algo.-quit
hacefind
que 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