이것은 간단해야 하지만 뭔가 빠졌고 도움이 필요합니다. 내 요구 사항은 최신 로그를 얻기 위해 로그 파일을 꼬리말로 읽고, 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 2
if 루프에서는 왜 작동하지 않습니까?
파이프는 서브쉘을 시작하고 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.file
server.log
더 이상 로그가 기록되지 않아 프로세스가 계속 열려 있음을 나타내는 경우 이는 특히 중요합니다.
답변2
tail -f
종료가 없으므로 "파일 중지" 확인과 로그 파일 읽기를 분리해야 합니다 . 다음 셸 스크립트는 "중지 파일"이 있는지 매초마다 백그라운드 작업을 확인하여 이를 수행합니다. 파일이 나타날 때마다 tail -f
신호( PIPE
읽기를 중지했을 때 수신한 것과 동일한 신호)로 프로세스를 종료합니다. 신호 로 인해 종료 grep
되면 입력 스트림이 닫히기 때문에 프로세스도 종료됩니다.tail -f
PIPE
grep
#!/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()
방법을 사용하면 여러 로그 파일을 동시에 쉽게 모니터링할 수도 있습니다.