조건이 충족되더라도 while 읽기 루프는 깨질 수 없습니다.

조건이 충족되더라도 while 읽기 루프는 깨질 수 없습니다.

이것은 간단해야 하지만 뭔가 빠졌고 도움이 필요합니다. 내 요구 사항은 최신 로그를 얻기 위해 로그 파일을 꼬리말로 읽고, grep을 사용하여 구성을 다운로드하고 모든 파일을 복사하여 MyOwnLogFile.log에 쓰는 것입니다. 하지만 .myworkisdone 파일이 /usr/local에 나타나면 이를 중지하고 싶습니다. /FOLDER / 한 가지 확실한 점은 모든 로그가 완료되면 마지막에 .myworkisdone이 생성된다는 것입니다. 하지만 파일이 생성되었음에도 스크립트는 로그 파일을 계속 읽고 종료하지 않습니다.

while [[ ! -e /usr/local/FOLDER/.myworkisdone ]];
do
    sudo tail -f -n0  /var/log/server22.log | while read line; do echo "$line" | grep -e 'Downloading Config’ -e ‘Copying all files of' ; done  >> /var/tmp/MyOwnLogFile.log
done

until또한 while 대신 파일 검사를 시도했지만 스크립트는 여전히 로그 파일을 읽는 마법을 깨뜨릴 수 없습니다. 미리 감사드립니다.

답변1

@ikkachu가 말했듯 tail -f이 이는 무한한 과정입니다. 그러나 내부 루프를 사용하여 인터럽트를 시작할 수 있습니다.

while :
do
    tail -f server.log | while IFS= read -r line
    do
        printf '%s\n' "$line" | grep 'word' >> ownlog.log
        if [ -e killer.file ] ; then break ; fi
    done
    break 
done
  • break 2if 루프에서는 왜 작동하지 않습니까?

파이프는 서브쉘을 시작하고 break명령은 서브쉘을 종료할 수 없습니다. 그래서 break외부 루프에 또 다른 것이 있습니다.

  • 스크립트는 언제 중지되나요?

일단 killer.file존재하면 보류 항목은 | while read ...여전히 ​​다른 항목을 기다리고 전체적으로 열려 있습니다. 즉, (더미 파일을 사용하여) 다음 줄이 필요합니다.

 echo test >> server.log
 #"normal" output - nothing happens

 echo word >> server.log
 #matching output - logged to ownlog.log
 
 touch killer.file
 #killer file appears - breaks cannot take effect
 #as "read" still awaits signal.

 echo test2 >> server.log
 #break takes effect

killer.fileserver.log더 이상 로그가 기록되지 않아 프로세스가 계속 열려 있음을 나타내는 경우 이는 특히 중요합니다.

답변2

tail -f종료가 없으므로 "파일 중지" 확인과 로그 파일 읽기를 분리해야 합니다 . 다음 셸 스크립트는 "중지 파일"이 있는지 매초마다 백그라운드 작업을 확인하여 이를 수행합니다. 파일이 나타날 때마다 tail -f신호( PIPE읽기를 중지했을 때 수신한 것과 동일한 신호)로 프로세스를 종료합니다. 신호 로 인해 종료 grep되면 입력 스트림이 닫히기 때문에 프로세스도 종료됩니다.tail -fPIPEgrep

#!/bin/sh

stopfile=/usr/local/FOLDER/.myworkisdone

set -- tail -f /var/log/server22.log 

"$@" | {
        while true; do
                if [ -e "$stopfile" ]; then
                        pkill -PIPE -fx "$*"
                        break
                fi
                sleep 1
        done &

        grep -e 'Downloading Config' \
             -e 'Copying all files of'
} >/var/tmp/MyOwnLogFile.log

이는 위치 매개변수를 tail -f명령에 설정합니다. 이렇게 하면 나중에 참조하기가 더 쉬워집니다 pkill. 이전에 시작한 명령을 정확히 종료할 수 있도록 두 pkill가지를 모두 사용하여 유틸리티를 호출합니다 .-f-x

값은 (기본적으로) 사이에 공백이 있는 모든 위치 매개변수(명령)로 구성된 "$*"문자열입니다 .tail -f

bash명명된 명령 배열을 사용하십시오 tail -f.

#!/bin/bash

stopfile=/usr/local/FOLDER/.myworkisdone

talicmd=( tail -f /var/log/server22.log )

"${tailcmd[@]}" | {
        while true; do
                if [ -e "$stopfile" ]; then
                        pkill -PIPE -fx "${tailcmd[*]}"
                        break
                fi
                sleep 1
        done &

        grep -e 'Downloading Config' \
             -e 'Copying all files of'
} >/var/tmp/MyOwnLogFile.log

grep(또한 질문에 사용된 정규 표현식 주위의 여러 작은따옴표가 일반 작은따옴표가 아니라 "멋진 따옴표"라는 사실도 확인했습니다.)

답변3

Perl에는 다음과 같은 모듈이 있습니다.파일::꼬리조건이 충족되면 프로그램이 조치를 취할 수 있도록 로그 파일을 모니터링하도록 설계되었습니다(예: 패턴이 일치하는 경우 줄 인쇄).

     #!/usr/bin/perl

     use File::Tail;
     tie *FH,"File::Tail",(name=>shift,nowait=>1);

     while (<FH>) {
         print if (m/Downloading Config|Copying all files of/);
         exit if ( -e '/usr/local/FOLDER/.myworkisdone')
     }

예를 들어 다른 이름으로 저장하여 watch.pl실행 가능하게 만들고 다음 chmod +x watch.pl과 같이 실행합니다.

$ ./watch.pl /var/log/server22.log

또는 awk 또는 sed 스크립트와 마찬가지로 쉘 스크립트에 한 줄의 코드로 삽입하면 됩니다.

perl -MFile::Tail -e 'tie *FH,"File::Tail",(name=>shift,nowait=>1);
      while (<FH>) {
        print if (m/Downloading Config|Copying all files of/);
        exit if ( -e '/usr/local/FOLDER/.myworkisdone')
      }' /var/log/server22.log

스크립트( name=>shift)의 첫 번째 매개변수로 명명된 로그 파일을 모니터링합니다. 이 패턴과 일치하는 모든 로그 파일 행을 인쇄하고 .myworkisdone 파일이 있으면 종료됩니다.

nowait=>1입력 파일을 읽는 동안 스크립트가 차단되는 것을 방지합니다. 이상적이지는 않지만 빠르고 지저분한 스크립트에는 적합합니다. 더 나은 해결책은 File::Tail select()메서드를 사용하는 것입니다. 바라보다 man File::Tail.

그런데 이 select()방법을 사용하면 여러 로그 파일을 동시에 쉽게 모니터링할 수도 있습니다.

관련 정보