저는 대학 연구실을 위해 아래 쉘 스크립트를 작성했습니다. 다른 프로세스에서 자주 업그레이드되는 로그 파일을 확인하고 호출 시 전달되는 여러 복사본을 생성해야 합니다. 다음은 코드입니다(logrotate.sh):
#!/bin/bash
# Usage:
# logrotate.sh [-n int] [-s signal] logfile
# where:
# int is an optional integer used to make int number of copies of logfile
# signal is the name of signal which shell command fuser must send to the process managing logfile
# this script lacks of a strong parameters checking
NCOPIES=4
LOGSIGNAL=USR1
#use of getopts to parse the arguments
while getopts "n:s:" OPTION ; do
case $OPTION in
n) NCOPIES="$OPTARG"
;;
s) LOGSIGNAL="$OPTARG"
;;
?) printf "Usage: %s [-n copies to keep] [-s signal to send] filename\n" $(basename $0) >&2
exit 1
;;
esac
done
#shift to read the last parameter (logfile)
shift $(($OPTIND - 1))
LOGFILE=$1
#create logfile.2 logfile.3 ... logfile.NCOPIES
for i in `seq $NCOPIES -1 1` ; do
test -f $LOGFILE.$i && mv $LOGFILE.$i $LOGFILE.$[ $i + 1 ]
done
mv $LOGFILE $LOGFILE.1
#sending signal to process which is writing to logfile to keep on writing to $LOGFILE(original name, without any extensions)
fuser -k -"$LOGSIGNAL" $LOGFILE.1
그래서 매초마다 파일에 쓰는 두 개의 스크립트를 작성했습니다.통나무:
-C 프로그램(로그테스트.c):
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("log", O_WRONLY | O_APPEND);
if(fd < 0 ){
printf("Impossible to open file %s.\n", "log");
return -1;
}
for(;;){
if(write(fd, "Ciao bello mio\n", 15) != 15){
write(2, "Error in writing data.\n", 23);
}
sleep(1);
}
close(fd);
exit(0);
}
-그리고 쉘 스크립트(로그테스트.sh):
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done
내가 시작할 때
./logtest.sh &
./logrotate.sh 로그
대본logrotate.sh올바른 이름의 모든 파일을 이동합니다(통나무된다로그.1) 파일을 소유한 프로세스에 신호를 보냅니다.통나무그 순간(그래서 쉘 스크립트는로그테스트.sh) 그런 다음 파일에 계속 씁니다.통나무. 게다가 퓨저로 보내는 신호에는 차이가 없는 것 같습니다. 퓨저가 항상 같은 방식으로 반응할 것입니다.
그러나 내가 실행하면
./logtest &
./logrotate.sh 로그
C 프로그램이로그 테스트명령으로부터 신호를 받습니다퓨저그런 다음 종료됩니다.
내 질문은: 왜 두 로깅 프로그램이 퓨저에서 전송된 신호에 대해 서로 다른 반응을 보이는가입니다. C 프로그램이 종료되는 동안 schell 스크립트는 계속 작동하는 이유는 무엇입니까?
RESTRICTIONS 섹션의 퓨저 매뉴얼 페이지에는 다음과 같이 나와 있습니다.
-k 옵션은 프로세스에서만 작동합니다.
쉘 스크립트가 쉘에서 실제 프로세스로 간주되지 않을 수 있습니까? 이것은 나에게 새로운 것입니다... 인터넷에서 검색했지만 관련 페이지를 찾을 수 없습니다.퓨저신호 섹션 안으로 깊숙이 들어가 보세요.
답변1
귀하의 스크립트는 파일 설명자 logtest.sh
에 즉시 쓰고 닫습니다. log
따라서 호출할 때 fuser
이 log.1
파일에 대한 활성 파일 설명자를 갖는 프로세스가 없습니다.
while
내부에서 루프를 실행하여 이를 시뮬레이션할 수 있습니다 .list
(while true; do echo $(date); sleep 1; done) >> log
그리고 신호를 처리하지 않기 때문에 무엇을 보내든 logtest.sh
및 둘 다 종료됩니다. 이 작업은 다음을 통해 수행할 수 있습니다 ( 참조 ). 그러나 나는 이것이 C에서 어떻게 수행되는지 전혀 모릅니다(C를 배운 적이 없습니다).logtest.c
SIGNAL
bash
trap '<COMMAND>' USR1
man bash-builtins
답변2
문제는 fuser
현재 커널에 파일 설명자가 열려 있는 파일을 사용하는 프로세스에서만 작동한다는 것입니다.
이는 프로그램에는 해당되지만 C
스크립트에는 해당되지 않습니다 bash
.
echo $(date) >> log
파일을 열고 추가한 stdout
다음 즉시 닫습니다. 따라서 파일은 fuser
의 확인 시 커널에 의해 열린 것으로 간주되지 않습니다 .
간단한 해결책은 루프가 끝날 bash
때까지 파일이 열려 있도록 스크립트를 변경하는 것입니다 while
.
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done < log
이런 방식으로 루프 시작 시 파일 설명자가 log
생성되고 루프가 끝날 while
때까지 열린 상태로 유지됩니다 .while