bash의 if test와 find 명령을 함께 사용하려면 어떻게해야합니까?


25

충돌 로그가있는 디렉토리가 있고 find 명령을 기반으로 bash 스크립트에서 조건문을 사용하고 싶습니다.

로그 파일은 다음 형식으로 저장됩니다.

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

지난 5 분 동안 수정 된 특정 앱에 대한 충돌 로그가있는 경우 if 문이 true를 반환하기를 원합니다. find내가 사용하는 것이 명령은 다음과 같습니다

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

나는 그것을 if올바르게 진술 에 통합하는 방법을 모르겠습니다 . 나는 이것이 효과가 있다고 생각한다.

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

확실하지 않은 몇 가지 영역이 있습니다.

  • 나는 if 플래그를 살펴 보았지만 어떤 플래그 를 사용해야하는지 잘 모르겠습니다.
  • test지시어 가 필요 find... | wc -l합니까? 아니면 find 명령의 결과에 대해 직접 처리해야합니까, 아니면 대신 행 수를 얻기 위해 사용해야 합니까?
  • 이 질문에 답하는 데 100 %가 필요하지는 않지만 test명령이 반환하는 반환 코드를 테스트하기위한 것입니까? 그리고 그들은 일종의 보이지 않는입니다 - 외부 stdout/ stderr? man페이지를 읽었 지만 언제 사용 test하고 언제 디버깅해야하는지 잘 모르겠습니다 .

일반적인 경우에 대한 실제 답변은를 사용하는 것 find ... -exec입니다. 또한 find의 출력이 루프 출력에 좋지 않은 이유는 무엇입니까?
와일드 카드

@Wildcard-불행히도 일반적인 경우를 해결 하지 못합니다 : 일치하는 항목이 두 개 이상이고 작업을 한 번만 실행 해야하는 경우 작동하지 않으며,있을 때 작업을 수행 해야하는 경우 작동하지 않습니다 맞지 않는다. 전자는을 사용하여 해결할 수 ... -exec command ';' -quit있지만 결과를 구문 분석하는 것 이외의 솔루션은 있다고 생각하지 않습니다. 또한 두 경우 모두 결과를 구문 분석 할 때 발생하는 주요 문제 find(예 : 파일 이름의 문자와 구분 기호를 구분할 수 없음)는 적용되지 않습니다. 이러한 경우 구분 기호를 찾을 필요가 없습니다.
Jules

답변:


27

[test동의어 (를 제외하고는 [필요 ]) 당신이 사용하지 않도록, [ test:

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

test조건이 true이면 0 종료 상태를 반환하고, 그렇지 않으면 0이 아닙니다. 실제로 종료 상태를 확인하기 위해 다른 프로그램으로 대체 할 수 있습니다. 여기서 0은 성공을 나타내고 0이 아닌 것은 실패를 나타냅니다.

# 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

그러나 위의 모든 예제는 프로그램의 종료 상태에 대해서만 테스트하고 프로그램의 출력을 무시합니다.

find경우 출력이 생성되었는지 테스트해야합니다. -n비어 있지 않은 문자열을 테스트합니다.

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

테스트 인수의 전체 목록은 명령 줄 help test에서 호출 하여 사용할 수 있습니다 bash.

당신이 사용하는 경우 bash(그리고 sh), 당신이 사용할 수있는 [[ condition ]]더 예측 가능한 당신의 상태에 공백 또는 기타 특별한 경우가있을 때 작동한다. 그렇지 않으면 일반적으로를 사용하는 것과 같습니다 [ condition ]. [[ condition ]]가능한 한 언제든지이 예제에서 사용 했습니다.

또한 변경 `command`$(command)또한 일반적으로 유사하게 동작하지만 중첩 된 명령 좋네요이다.


echo실패 할 수 있습니다 : 시도하십시오 echo 'oops' > /dev/full.
derobert

이 답변은 문제의 근본 원인을 모두 능가하지만 정확히 무엇인지 언급하지 않아도됩니다.
bahamat

9

find오류가 없으면 성공적으로 종료되므로 종료 상태를 계산하여 파일을 찾았는지 알 수 없습니다. 그러나 당신이 말했듯이, 당신은 그것을 발견 한 파일의 수를 세고 그 수를 테스트 할 수 있습니다.

다음과 같습니다.

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

test(aka [)는 명령의 오류 코드를 확인하지 않으며 테스트를 수행하는 특수 구문이 있으며 테스트가 성공하면 0, 그렇지 않으면 1이 오류 코드로 종료됩니다. 이다 if수표 당신이 그것에 전달하는 명령의 오류 코드, 그것을 기반으로 몸을 실행하는 사람.

참조 man test(또는 help test, 당신이 사용하는 경우 bash) 및 help if(저두 요).

이 경우 wc -l숫자를 출력합니다. 해당 test옵션 -gt이 숫자보다 큰지 테스트하기 위해 옵션 을 사용 0합니다. 그렇다면 test(또는 [) 종료 코드와 함께 반환됩니다 0. if종료 코드를 성공으로 해석하고 본문 내에서 코드를 실행합니다.


1

이것은

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

또는

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

명령 test[ … ]정확히 동의어입니다. 유일한 차이점은 그들의 이름과 마지막 논쟁으로 [종결 이 필요한 사실입니다 ]. 항상 그렇듯이 명령 치환에 큰 따옴표를 사용하십시오. 그렇지 않으면 명령의 출력이 find단어로 나뉩니다. 여기서 일치하는 파일이 둘 이상인 경우 (그리고 인수가없는 경우에 해당하면 구문 오류가 발생 [ -n ]합니다) , 당신은 [ -n "" ]어느 것이 거짓 인지 원합니다 ).

ksh, bash 및 zsh에서는 ash가 아닌 [[ … ]]다른 구문 분석 규칙을 사용할 수도 있습니다 [. 일반적인 명령 [[ … ]]은 다른 구문 분석 구문입니다. 안에 큰 따옴표가 필요 [[ … ]]하지 않습니다 (아프지 않더라도). 여전히 ;사후 명령이 필요합니다 .

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

에 잠재적으로 비효율적 /var/log/crashes일 수 있습니다.에 파일이 많으면 찾기가 파일을 모두 탐색합니다. 일치하는 것을 찾 자마자 또는 찾기 후에 찾기를 중지해야합니다. GNU find (포함되지 않은 Linux, Cygwin)에서는 -quit기본을 사용하십시오 .

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

다른 시스템의 경우 첫 번째 일치 직후 파이프 findhead종료하십시오 (파손 된 파이프로 찾기).

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

( 명령이 지원 하는 head -c 1경우 사용할 수 있습니다 head.)


또는 zsh를 사용하십시오.

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

1

이 작동합니다

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

0
find /var/log/crashes -name app-\*\.log -mmin -5 -exec service myapp restart ';' -quit

여기에 적절한 솔루션입니다.

-exec service myapp restart ';'원인 find은 오히려 아무것도 해석 쉘을 필요로하는 것보다 직접 실행하려는 명령을 호출 할 수 있습니다.

-quit원인이 find조건에 맞는 여러 개의 파일이있을 일어나는 경우에 따라서 다시 실행되는 명령을 방지 명령을 처리 한 후 종료합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.