![Unterschied zwischen C-Programmen und Shell-Skripten, die Signale vom Fuser empfangen](https://rvso.com/image/1126777/Unterschied%20zwischen%20C-Programmen%20und%20Shell-Skripten%2C%20die%20Signale%20vom%20Fuser%20empfangen.png)
Ich habe das folgende Shell-Skript für ein Labor an meinem College geschrieben. Es muss eine Protokolldatei prüfen, die häufig von einem anderen Prozess aktualisiert wird, und eine Anzahl von Kopien erstellen, die beim Aufruf übergeben werden. Hier ist der Code (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
Also schrieb ich zwei Skripte, die jede Sekunde in die Datei schreibenProtokoll:
-das C-Programm (logtest.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);
}
-und das Shell-Skript (logtest.sh):
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done
Wenn ich starte
./logtest.sh und
./logrotate.sh Protokoll
Das Skriptlogrotate.shverschiebt alle Dateien mit den richtigen Namen (Protokollwirdlog.1) und senden Sie das Signal an den Prozess, dem die Datei gehörtProtokollfür diesen Moment (also das Shell-Skriptlogtest.sh), das dann weiter in die Datei schreibtProtokoll. Darüber hinaus scheint es keinen Unterschied zu machen, welches Signal ich mit Fuser sende: Es reagiert immer auf die gleiche Weise.
Wenn ich jedoch starte
./logtest und
./logrotate.sh-Protokoll
kommt es vor, dass das C-ProgrammProtokolltestempfängt das Signal vom KommandoFixiereinheitund wird dann beendet.
Meine Frage ist: Warum reagieren die beiden Protokollierungsprogramme unterschiedlich auf das vom Fuser gesendete Signal? Ich meine, warum läuft das Schell-Skript weiter, während das C-Programm beendet wird?
In der Manpage von fuser heißt es im Abschnitt RESTRICTIONS
Die Option -k funktioniert nur bei Prozessen.
Könnte es sein, dass Shell-Skripte in der Shell nicht als echte Prozesse betrachtet werden? Das wäre neu für mich... Ich habe im Internet gesucht, aber keine Seite gefunden überFixiereinheitGehen Sie tief in den Signalabschnitt.
Antwort1
Ihr Skript logtest.sh
schreibt nur in log
den Dateideskriptor und schließt ihn sofort wieder. Wenn Sie also aufrufen, fuser
gibt log.1
es keinen Prozess, der einen aktiven Dateideskriptor für diese Datei hat.
Sie können dies simulieren, indem Sie die while
Schleife innerhalb eineslist
(while true; do echo $(date); sleep 1; done) >> log
Und sowohl als logtest.sh
auch logtest.c
werden beendet, egal welches SIGNAL
Sie senden, da Sie das Signal nicht verarbeiten. bash
Dies kann mit gemacht werden trap '<COMMAND>' USR1
(sehen Sie sich an man bash-builtins
). Aber ich habe keine Ahnung, wie das in C gemacht wird (habe C nie gelernt).
Antwort2
Das Problem besteht darin, dass dies fuser
nur bei Prozessen funktioniert, die aktuell eine Datei verwenden und für die im Kernel ein geöffneter Dateideskriptor vorhanden ist.
Dies trifft zwar auf Ihr C
Programm zu, nicht jedoch auf Ihr bash
Skript:
echo $(date) >> log
Öffnet einfach die Datei, hängt etwas stdout
daran an und schließt sie sofort wieder. Daher wird die Datei vom Kernel bei fuser
der Überprüfung nie als geöffnet betrachtet.
Eine einfache Lösung wäre, Ihr bash
Skript so zu ändern, dass die Datei geöffnet bleibt, bis die while
Schleife endet:
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done < log
Auf diese Weise wird beim Start der Schleife ein Dateideskriptor log
erstellt und bis zum Ende der Schleife while
geöffnet gehalten .while