![C程式和shell腳本從fuser接收訊號的區別](https://rvso.com/image/1126777/C%E7%A8%8B%E5%BC%8F%E5%92%8Cshell%E8%85%B3%E6%9C%AC%E5%BE%9Efuser%E6%8E%A5%E6%94%B6%E8%A8%8A%E8%99%9F%E7%9A%84%E5%8D%80%E5%88%A5.png)
我為我大學的一個實驗室編寫了下面的 shell 腳本。它必須查看從另一個進程頻繁升級的日誌文件,並創建在呼叫時傳遞的多個副本。這是代碼(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);
}
- 和 shell 腳本 (日誌測試.sh):
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done
當我啟動時
./logtest.sh &
./logrotate.sh 日誌
劇本logrotate.sh移動所有具有正確名稱的檔案(紀錄變成日誌.1)並將訊號傳送到擁有該檔案的進程紀錄那一刻(所以 shell 腳本日誌測試.sh)然後繼續寫入文件紀錄。此外,我用定影器發送的信號似乎沒有區別:它總是以相同的方式做出反應。
但是,如果我啟動
./logtest &
./logrotate.sh 日誌
碰巧 C 程序對數測試接收來自命令的訊號定影器然後終止。
我的問題是:為什麼兩個日誌程式對從定影器發送的訊號有不同的反應?我的意思是,為什麼 schel 腳本繼續工作,而 C 程式終止?
在定影器的手冊頁的限制部分中,它說
-k 選項僅適用於進程。
難道shell腳本不被認為是shell中的真實進程嗎?這對我來說是新的......我在互聯網上搜索過,但沒有找到有關的頁面定影器深入了解訊號部分。
答案1
您的腳本logtest.sh
只會立即寫入log
並關閉檔案描述符。因此,當您呼叫時,fuser
沒有log.1
進程具有該檔案的活動檔案描述符。
while
您可以透過在 a 中運行循環來模擬這一點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
這樣,文件描述符 forlog
在循環開始時創建while
,並保持打開狀態直到while
循環結束。