bash의 if test와 find 명령을 동시에 사용하는 방법은 무엇입니까?

bash의 if test와 find 명령을 동시에 사용하는 방법은 무엇입니까?

충돌 로그가 포함된 디렉토리가 있고 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

내가 잘 이해하지 못하는 몇 가지 사항이 있습니다.

  • 나는 본 적이플래그가 있는 경우하지만 어떤 것을 사용해야 할지 잘 모르겠습니다.
  • 해당 지시어가 필요합니까 test, 아니면 find 명령의 결과를 직접 처리해야 합니까, 아니면 이를 사용하여 find... | wc -l행 수를 얻을 수 있습니까?
  • 이 질문에 100% 대답할 필요는 없지만 test명령에서 반환된 반환 코드를 테스트하기 위한 것입니까? 보이지 않는가? 내부 stdout/외부 stderr? 페이지 를 읽었 man지만 언제 사용 test하고 디버깅하는 방법이 여전히 명확하지 않습니다.

답변1

[test동의어( [require 제외 ])이므로 다음을 사용하고 싶지 않습니다 [ 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)

답변2

find오류 없이 성공적으로 종료되므로 종료 상태에 의존하여 파일을 찾았는지 확인할 수 없습니다. 하지만 말씀하신 대로 얼마나 많은 파일을 찾았는지 계산하고 그 수를 테스트할 수 있습니다.

다음과 같이 보일 것입니다:

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

test(일명 [)은 명령의 오류 코드를 확인하지 않으며 이를 테스트하는 특수 구문이 있으며 테스트에 성공하면 오류 코드 0으로 종료하고 그렇지 않으면 1로 종료합니다. if전달한 명령의 오류 코드를 확인하고 이를 기반으로 본문을 실행합니다 .

man test(또는 help test을 사용하는 경우 bash) 및 help if(ibid.)를 참조하세요 .

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

답변3

이것은 ~이 될 것이다

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합니다 . [ … ]유일한 차이점은 이름과 마지막 매개변수로 [end가 필요하다는 점입니다. ]항상 그렇듯이 명령 대체에는 큰따옴표를 사용하십시오. 그렇지 않으면 명령의 출력이 find단어로 나누어지고 일치하는 파일이 여러 개 있는 경우 구문 오류가 발생합니다(인수가 없는 경우 true [ -n ]). 그러나 원하는 [ -n "" ]것은 잘못된 것입니다. .

ksh, bash 및 zsh에서는 ash가 아닌 [[ … ]]다른 구문 분석 규칙을 사용하여 사용할 수도 있습니다. 이는 [일반 명령 [[ … ]]이지만 구문 분석 구조가 다릅니다. 내부에 큰따옴표를 사용할 필요는 없습니다 [[ … ]](해롭지는 않지만). ;명령 뒤에 오는 내용이 여전히 필요합니다 .

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

이는 비효율적일 수 있습니다. 에 파일이 많으면 /var/log/crashesfind가 해당 파일을 모두 탐색합니다. 일치하는 항목을 찾은 직후 또는 즉시 검색을 중지해야 합니다. GNU find(비임베디드 Linux, Cygwin)에서는 기본 -quit.

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

다른 시스템의 경우 파이프 find입구는 head최소한 첫 번째 일치 직후에 종료됩니다(파이프가 파손된 것을 발견하면 사망하게 됩니다).

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

답변4

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

적합한 솔루션입니다.

-exec service myapp restart ';'find쉘이 아무것도 해석하지 않고 직접 실행하려는 명령이 호출 되도록 합니다 .

-quit처리 후 명령이 종료되도록 하여 find둘 이상의 파일이 조건과 일치하는 경우 명령이 다시 실행되지 않도록 합니다.

관련 정보