Eu tenho um diretório com logs de falha e gostaria de usar uma instrução condicional em um script bash com base em um comando find.
Os arquivos de log são armazenados neste formato:
/var/log/crashes/app-2012-08-28.log
/var/log/crashes/otherapp-2012-08-28.log
Desejo que a instrução if retorne true somente se houver um log de falha para um aplicativo específico que foi modificado nos últimos 5 minutos. O find
comando que eu usaria é:
find /var/log/crashes -name app-\*\.log -mmin -5
Não sei como incorporar isso a uma if
declaração corretamente. Eu acho que isso pode funcionar:
if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then
service myapp restart
fi
Existem algumas áreas em que não estou claro:
- Eu olhei para os sinalizadores if, mas não tenho certeza de qual deles, se houver, que devo usar.
- Preciso da
test
diretiva ou devo apenas processar diretamente os resultados do comando find ou usarfind... | wc -l
para obter uma contagem de linhas? - Não é 100% necessário para responder a essa pergunta, mas
test
é para testar contra códigos de retorno que comandos retornam? E eles são meio invisíveis - fora destdout
/stderr
? Eu li aman
página, mas ainda não sou muito claro sobre quando usartest
e como depurá-la.
find ... -exec
. Veja também os comandos de exemplo em Por que é um loop sobre a prática recomendada de saída do find?... -exec command ';' -quit
, mas não creio que exista outra solução para além do que seja analisar o resultado. Além disso, em ambos os casos, o principal problema com a análise do resultado defind
(ou seja, incapacidade de distinguir delimitadores de caracteres nos nomes de arquivos) não se aplica, pois você não precisa encontrar delimitadores nesses casos.Respostas:
[
etest
são sinônimos (exceto[
requer]
), então você não deseja usar[ test
:test
retorna um status de saída zero se a condição for verdadeira, caso contrário, diferente de zero. Na verdade, isso pode ser substituído por qualquer programa para verificar seu status de saída, onde 0 indica sucesso e diferente de zero indica falha:No entanto, todos os exemplos acima são testados apenas contra o status de saída do programa e ignoram a saída do programa.
Para
find
, você precisará testar se alguma saída foi gerada.-n
testes para uma string não vazia:Uma lista completa dos argumentos de teste está disponível chamando
help test
nabash
linha de comando.Se você estiver usando
bash
(e nãosh
), poderá usar o[[ condition ]]
que se comporta de maneira mais previsível quando houver espaços ou outros casos especiais em sua condição. Caso contrário, geralmente é o mesmo que usar[ condition ]
. Eu usei[[ condition ]]
neste exemplo, como sempre que possível.Também mudei
`command`
para$(command)
, que geralmente também se comporta de maneira semelhante, mas é mais agradável com comandos aninhados.fonte
echo
pode falhar: tenteecho 'oops' > /dev/full
.find
sairá com êxito se não houver erros; portanto, você não pode contar com o status de saída para saber se encontrou algum arquivo. Mas, como você disse, você pode contar quantos arquivos foram encontrados e testar esse número.Seria algo como isto:
test
(aka[
) não verifica os códigos de erro dos comandos, possui uma sintaxe especial para realizar testes e sai com um código de erro 0 se o teste foi bem-sucedido ou 1 caso contrário. Éif
aquele que verifica o código de erro do comando que você passa para ele e executa seu corpo com base nele.Consulte
man test
(ouhelp test
, se você usarbash
) ehelp if
(idem).Nesse caso,
wc -l
produzirá um número. Usamostest
a opção-gt
para testar se esse número é maior que0
. Se for,test
(ou[
) retornará com o código de saída0
.if
interpretará esse código de saída como bem-sucedido e executará o código dentro de seu corpo.fonte
Este seria
ou
Os comandos
test
e[ … ]
são exatamente sinônimos. A única diferença é o nome e o fato de[
exigir um fechamento]
como último argumento. Como sempre, use aspas duplas em torno da substituição do comando, caso contrário, a saída dofind
comando será dividida em palavras e aqui você receberá um erro de sintaxe se houver mais de um arquivo correspondente (e quando não houver argumentos,[ -n ]
for verdadeiro , enquanto você deseja o[ -n "" ]
que é falso).No ksh, bash e zsh, mas não no ash, você também pode usar o
[[ … ]]
que possui regras de análise diferentes:[
é um comando comum, enquanto que[[ … ]]
é uma construção de análise diferente. Você não precisa de aspas duplas dentro[[ … ]]
(embora elas não doam). Você ainda precisa do;
após o comando.Isso pode ser potencialmente ineficiente: se houver muitos arquivos
/var/log/crashes
, o find irá explorar todos eles. Você deve fazer a busca parar assim que encontrar uma correspondência ou logo depois. Com o GNU find (Linux não incorporado, Cygwin), use o-quit
primário.Com outros sistemas, entre
find
no tubohead
para pelo menos sair logo após a primeira partida (a localização morrerá de um tubo quebrado).(Você pode usar
head -c 1
se o seuhead
comando suportar.)Como alternativa, use zsh.
fonte
Isso deve funcionar
fonte
é uma solução apropriada aqui.
-exec service myapp restart ';'
fazfind
com que invoque o comando que você deseja executar diretamente, em vez de precisar que o shell interprete qualquer coisa.-quit
fazfind
com que saia após o processamento do comando, impedindo que o comando seja executado novamente se houver vários arquivos que correspondam aos critérios.fonte