1. The concept and reason of I/O redirection and standard error definition of standard input and output
So UNIX I/O redirection is based on the principle of standard data flow. Of the three data were as follows:
1) standard input-the data stream to be processed
2) Standard output--result data stream
3) standard error output--error message Flow
Concept: So the UNIX tools use file descriptors 0, 1, and 2. The standard input file descriptor is 0, the standard output file descriptor is 1, and the standard error output file descriptor is 2. UNIX assumes that the file descriptor 0, 1, 2 has been opened, can be read and write operations separately.
Typically, stdin, stdout, and stderr are connected to the terminal when running UNIX system tools from the shell command line. Therefore, the tool reads the data from the keyboard and writes the output and error messages to the screen.
Most UNIX tools process data that is read from a file or standard input. If a file name is given on the command line, the tool reads the data from the file. If there is no file name, the program reads the data from the standard input. On the other hand, most programs do not receive the output file name; they always write the result to the file descriptor 1 and write the error message to the file descriptor 2. If you want to write the output of a process to a file or another process input, you must redirect the corresponding file descriptor.
Redirect I/O is the shell and not the program
Lowest available file descriptor (LOWEST-AVAILABLE-FD) Principle: A file descriptor is an index number of an array. Each process has its own set of files open. These open files are kept in an array. The file descriptor is the index of a file in this array. When you open a file, the descriptor that is scheduled for this file is always the index of the lowest available location in this array.
Use the concept of file descriptors 0, 1, 2, and the minimum available file descriptor principles to understand how I/O redirection works
2. REDIRECT Standard I/O to file
(1) How to direct stdin to a file
A, Close-then-open strategy
Close (0); int fd = open (file, o_rdonly);
B, Open-close-dup-close strategy
int OLDFD = open (file, o_rdonly); #ifndef DUP2 Close (0); int newfd = DUP (OLDFD), #else int newfd = dup2 (OLDFD, 0); #endifclose (OLDFD);
Mans 2 DUP
#include <unistd.h>int dup (int oldfd), int dup2 (int oldfd, int newfd);
The system calls DUP to copy the file descriptor OLDFD. Instead, dup2 copies the oldfd file descriptor to NEWFD. Two file descriptors point to the same open file. Both calls return a new file descriptor, or 1 if an error occurs.
C, Open-dup2-close Strategy
(2) Redirect to file
There are 3 basic concepts, and using them is a program under UNIX that can easily connect standard input, output, and error message output to a file:
A, standard input, output, and error outputs correspond to file descriptors 0, 1, 2, respectively;
B, the kernel always uses the lowest available file descriptor;
C, the file descriptor collection is passed by the exec call and is not changed.
Example:
/* * WHO_TO_FILE.C * purpose:show How to redirect output for another program * idea:fork, then in the child, redirect OU Tput, then exec * * #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/ Wait.h>int Main (void) { pid_t pid; int FD; printf ("About-to-run who into a file\n"); /* Create a new process or quit */ if ((PID = fork ()) = =-1) { perror ("fork"); Exit (1); } /* Child does the work */ if (PID = = 0) { close (1); FD = creat ("userlist", 0644); EXECLP ("Who", "who", NULL); Perror ("EXECLP"); Exit (1); } /* Parent Waits then reports * /else { wait (NULL); printf ("Done running". Results in userlist\n "); } return 0;}
3. Pipeline Programming
(1) Create a pipeline
Man 2 pipe
#include <unistd.h>int pipe (int pipefd[2]);
The system calls pipe to create a pipe and connects both ends to two file descriptors. PIPEFD[0] is the file descriptor of the read data side, and Pipefd[1] is the file descriptor of the write data side.
(2) Technical details: Pipeline is not a document
A. Read data from the pipeline
Pipeline Read blocking: When a process attempts to read data from a pipeline, the process is suspended until the data is written into the pipeline.
Read end flag for pipe: When the write operation closes the write data end of the pipeline, the call to read the data from the pipe returns 0, which means the end of the file.
Multiple read operations can cause trouble: The pipeline is a queue. After the process has read the data from the pipeline, the data no longer exists.
B. Write data to the pipeline
Write data blocking until pipeline has room to accommodate new data
The write must guarantee a minimum block size: The POSIX standard specifies that the connotation does not split blocks smaller than 512 bytes. Linux, however, guarantees that 4096 bytes of contiguous cache can exist in the pipeline. If two processes write data to the pipeline, and none of the processes restricts its messages from being hit because of 512 bytes, the messages are not split by the kernel.
If no read operation is reading the data, the write operation fails: If so the read operation has closed the read side of the pipeline, then the write call to the pipeline will fail. If in this case the data can also be received, in order to avoid data loss, the kernel uses two methods to inform the process: "The write operation at this time is meaningless". First, the kernel sends sigpipe messages to the process. If the process is terminated, nothing happens. Otherwise, the write call returns-1, and the errno is set to Epipe.
Example:
/* * PIPE.C-* Demonstrates how to create a pipeline from one process to another * takes both args, each a command, a nd connectes * argv[1]s output to input of argv[2] * usage:pipe command1 command2 * effect:command1 | Command2 * Limitations:commands Don't take arguments * users EXECLP () since known number of args * note:exchange child and parent and watch fun */#include <stdio.h> #include <stdlib.h> #include <unistd.h> #define OOPS (m, x) { Perror (m); Exit (x); }int Main (int argc, char **argv) {int thepipe[2], NEWFD, PID; if (argc! = 3) {fprintf (stderr, "usage:./pipe cmd1 cmd2\n"); Exit (1); } if (pipe (thepipe) = =-1) oops ("Cannot get a pipe", 1); if (PID = fork ()) = =-1) oops ("Cannot fork", 2); if (PID > 0) {close (thepipe[1]); if (Dup2 (Thepipe[0], 0) = =-1) oops ("Could not redirect stdin", 3); Close (thepipe[0]); EXECLP (Argv[2], argv[2], NULL); Oops (argv[2], 4); } close (thepipe[0]); if (Dup2 (thepipe[1], 1) = =-1) oops ("Could not redirect stdout", 4); Close (thepipe[1]); EXECLP (Argv[1], argv[1], NULL); Oops (argv[1], 5); return 0;}