Auf einem älteren RHEL System , das ich habe, /bin/cat
tut nicht Schleife für cat x >> x
. cat
gibt die Fehlermeldung "cat: x: Eingabedatei ist Ausgabedatei" aus. Ich kann täuschen , /bin/cat
indem Sie diese: cat < x >> x
. Wenn ich Ihren obigen Code ausprobiere, erhalte ich die von Ihnen beschriebene "Schleife". Ich habe auch einen Systemaufruf geschrieben, der auf "cat" basiert:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int
main(int ac, char **av)
{
char buf[4906];
int fd, cc;
fd = open(av[1], O_RDONLY);
while ((cc = read(fd, buf, sizeof(buf))) > 0)
if (cc > 0) write(1, buf, cc);
close(fd);
return 0;
}
Dies ist auch eine Schleife. Die einzige Pufferung hier (im Gegensatz zu stdio-basierten "mycat") ist, was im Kernel vor sich geht.
Ich denke, was passiert ist, dass Dateideskriptor 3 (das Ergebnis von open(av[1])
) einen Versatz in die Datei von 0 hat. Abgelegtes Deskriptor 1 (stdout) hat einen Versatz von 3, weil das ">>" die aufrufende Shell veranlasst, ein lseek()
auf dem Dateideskriptor, bevor er an den cat
untergeordneten Prozess übergeben wird.
Wenn Sie eine read()
beliebige Art ausführen, sei es in einem Stdio-Puffer oder in einer Ebene, wird char buf[]
die Position des Dateideskriptors vorgerückt. 3. Wenn Sie eine beliebige Art ausführen, wird write()
die Position des Dateideskriptors vorgerückt. Aufgrund des ">>" hat Dateideskriptor 1 immer einen Versatz, der größer oder gleich dem Versatz von Dateideskriptor 3 ist. Daher wird jedes "katzenartige" Programm eine Schleife ausführen, es sei denn, es führt eine interne Pufferung durch. Es ist möglich, vielleicht sogar wahrscheinlich, dass eine stdio-Implementierung von a FILE *
(das ist der Typ der Symbole stdout
und f
in Ihrem Code) einen eigenen Puffer enthält. fread()
kann tatsächlich einen Systemaufruf ausführen read()
, um den internen Puffer fo zu füllen f
. Dies kann oder kann nichts an den Innenseiten von ändern stdout
. Ich rufe fwrite()
anstdout
kann oder kann nichts innerhalb von ändern f
. Eine stdio-basierte "Katze" kann also keine Schleife bilden. Oder es könnte. Schwer zu sagen, ohne viel hässlichen, hässlichen libc-Code durchzulesen.
Ich habe eine strace
auf dem RHEL cat
- es macht nur eine Abfolge von read()
und write()
Systemaufrufen. Aber so cat
muss man nicht arbeiten. Es wäre dann möglich mmap()
die Eingabedatei zu machen write(1, mapped_address, input_file_size)
. Der Kernel würde die ganze Arbeit machen. sendfile()
Auf Linux-Systemen können Sie auch einen Systemaufruf zwischen den Eingabe- und Ausgabedateideskriptoren ausführen. Es wurde gemunkelt, dass alte SunOS 4.x-Systeme den Memory-Mapping-Trick ausführen, aber ich weiß nicht, ob jemals jemand eine sendfile-basierte Katze erstellt hat. In jedem Fall wäre die „Looping“ nicht passieren, da beide write()
und sendfile()
erfordern eine Länge-zu-Übertragungsparameter.