Mam katalog z dziennikami awarii i chciałbym użyć instrukcji warunkowej w skrypcie bash opartym na poleceniu find.
Pliki dziennika są przechowywane w tym formacie:
/var/log/crashes/app-2012-08-28.log
/var/log/crashes/otherapp-2012-08-28.log
Chcę, aby instrukcja if zwróciła wartość true tylko wtedy, gdy istnieje dziennik awarii dla konkretnej aplikacji, która została zmodyfikowana w ciągu ostatnich 5 minut. find
Poleceń, które używam to:
find /var/log/crashes -name app-\*\.log -mmin -5
Nie jestem pewien, jak if
poprawnie włączyć to do oświadczenia. Myślę, że to może działać:
if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then
service myapp restart
fi
Jest kilka obszarów, w których jestem niejasny:
- Patrzyłem na flagi if, ale nie jestem pewien, który z nich, jeśli w ogóle, powinienem użyć.
- Czy potrzebuję
test
dyrektywy, czy powinienem po prostu przetwarzać bezpośrednio wyniki polecenia find, czy możefind... | wc -l
zamiast tego użyć licznika wierszy? - Nie jest w 100% konieczne, aby odpowiedzieć na to pytanie, ale
test
czy do testowania kodów powrotu komendy return? I są jakby niewidoczne - pozastdout
/stderr
? Czytamman
stronę, ale wciąż nie jestem pewien, kiedy używaćtest
i jak ją debugować.
find ... -exec
. Zobacz także przykładowe polecenia w sekcji Dlaczego zapętlanie wyników wyszukiwania jest złą praktyką?... -exec command ';' -quit
, ale nie sądzę, że istnieje drugie rozwiązanie poza analizowaniem wyniku. W obu przypadkach główny problem z analizowaniem wynikufind
(tj. Niemożność odróżnienia ograniczników od znaków w nazwach plików) nie ma zastosowania, ponieważ w takich przypadkach nie trzeba znajdować ograniczników.Odpowiedzi:
[
itest
są synonimami (z wyjątkiem[
wymaga]
), więc nie chcesz używać[ test
:test
zwraca zerowy status wyjścia, jeśli warunek jest spełniony, w przeciwnym razie niezerowy. Można to faktycznie zastąpić dowolnym programem, aby sprawdzić jego status wyjścia, gdzie 0 oznacza sukces, a niezerowy oznacza błąd:Jednak wszystkie powyższe przykłady testują tylko status wyjścia programu i ignorują dane wyjściowe programu.
Dla
find
, trzeba będzie testem gdy moc wyjściowa została wygenerowana.-n
testy niepustego ciągu:Pełna lista argumentów testowych jest dostępna po wywołaniu
help test
wbash
wierszu polecenia.Jeśli używasz
bash
(i nie używaszsh
), możesz użyć[[ condition ]]
, który zachowuje się bardziej przewidywalnie, gdy w twoim stanie są spacje lub inne specjalne przypadki. W przeciwnym razie jest to ogólnie to samo, co używanie[ condition ]
. Użyłem[[ condition ]]
tego przykładu, tak jak zawsze, gdy to możliwe.Zmieniłem również
`command`
na$(command)
, który również ogólnie zachowuje się podobnie, ale jest ładniejszy dzięki zagnieżdżonym poleceniom.źródło
echo
może zawieść: spróbujecho 'oops' > /dev/full
.find
zakończy się pomyślnie, jeśli nie wystąpiły żadne błędy, więc nie możesz liczyć na jego status wyjścia, aby wiedzieć, czy znalazł jakiś plik. Ale, jak powiedziałeś, możesz policzyć liczbę znalezionych plików i przetestować tę liczbę.Byłoby to coś takiego:
test
(aka[
) nie sprawdza kodów błędów poleceń, ma specjalną składnię do wykonywania testów, a następnie kończy działanie z kodem błędu 0, jeśli test się powiódł, lub 1 w przeciwnym razie. Toif
ten, który sprawdza kod błędu polecenia, które mu przekazujesz, i wykonuje na nim swoje ciało.Zobacz
man test
(lubhelp test
, jeśli używaszbash
) ihelp if
(to samo).W takim przypadku
wc -l
wyświetli liczbę. Używamytest
opcji,-gt
aby sprawdzić, czy liczba ta jest większa niż0
. Jeśli tak,test
(lub[
) zwróci kod wyjścia0
.if
zinterpretuje ten kod wyjścia jako sukces i uruchomi kod w swoim ciele.źródło
To byłoby
lub
Polecenia
test
i[ … ]
są dokładnie synonimami. Jedyną różnicą jest ich nazwa i fakt, który[
wymaga zamknięcia]
jako ostatniego argumentu. Jak zawsze, używaj podwójnych cudzysłowów wokół podstawiania polecenia, w przeciwnym razie dane wyjściowefind
polecenia zostaną podzielone na słowa, a tutaj otrzymasz błąd składniowy, jeśli istnieje więcej niż jeden pasujący plik (a gdy nie ma argumentów,[ -n ]
to prawda , podczas gdy chcesz,[ -n "" ]
co jest fałszywe).W ksh, bash i zsh, ale nie w ash, możesz również użyć,
[[ … ]]
który ma różne reguły parsowania:[
jest zwykłym poleceniem, podczas gdy[[ … ]]
jest inną konstrukcją parsowania. W środku nie potrzebujesz podwójnych cudzysłowów[[ … ]]
(choć nie bolą). Nadal potrzebujesz polecenia;
po.Może to być potencjalnie nieefektywne: jeśli jest wiele plików
/var/log/crashes
, find zbada je wszystkie. Powinieneś zatrzymać wyszukiwanie, jak tylko znajdzie dopasowanie, lub wkrótce potem. W przypadku GNU find (niewbudowany Linux, Cygwin) użyj-quit
podstawowego.Z innymi systemami, rury
find
językhead
przynajmniej rzucić wkrótce po pierwszym meczu (Znajdź umrze z powodu złamanego rury).(Możesz użyć,
head -c 1
jeśli twojehead
polecenie to obsługuje.)Alternatywnie użyj zsh.
źródło
To powinno działać
źródło
jest tutaj odpowiednim rozwiązaniem.
-exec service myapp restart ';'
powodujefind
wywołanie polecenia, które chcesz uruchomić bezpośrednio, zamiast konieczności interpretowania powłoki przez powłokę.-quit
powodujefind
zakończenie działania po przetworzeniu polecenia, co zapobiega ponownemu wykonaniu polecenia, jeśli zdarzy się, że będzie wiele plików spełniających kryteria.źródło