0% found this document useful (0 votes)
35 views60 pages

I/O and Process Management!: Jennifer Rexford!

The document discusses I/O and process management in Unix systems. It covers the stream abstraction in Unix, standard I/O functions in C like fopen() and fprintf(), and lower-level system calls like open(), read(), and write(). It also discusses creating new processes using fork() and advantages like running programs concurrently. Buffered I/O is described as an optimization where data is read and written in larger chunks to reduce system calls.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views60 pages

I/O and Process Management!: Jennifer Rexford!

The document discusses I/O and process management in Unix systems. It covers the stream abstraction in Unix, standard I/O functions in C like fopen() and fprintf(), and lower-level system calls like open(), read(), and write(). It also discusses creating new processes using fork() and advantages like running programs concurrently. Buffered I/O is described as an optimization where data is read and written in larger chunks to reduce system calls.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 60

I/O and Process Management!

Jennifer Rexford!

1
Goals of this Lecture: I/O!
The Unix stream concept!
Standard C I/O functions!
Unix system-level functions for I/O!
How C I/O functions use the Unix functions!
Additional abstractions provided by C I/O functions!

Streams are a beautiful Unix abstraction!

2
Stream Abstraction!
Any source of input or destination for output!
E.g., keyboard as input, and screen as output!
E.g., files on disk or CD, network ports, printer port, !

Accessed in C programs through file pointers!


E.g., FILE *fp1, *fp2;
E.g., fp1 = fopen("myfile.txt", "r");

Three streams provided by stdio.h!


Streams stdin, stdout, and stderr!
Typically map to keyboard, screen, and screen!
Can redirect to correspond to other streams!
E.g., stdin can be the output of another program!
E.g., stdout can be the input to another program! 3
Sequential Access to a Stream!
Each stream has an associated file position!
Starting at beginning of file (if opened to read or write)!
Or, starting at end of file (if opened to append)!

file file

Read/write operations advance the file position!


Allows sequencing through the file in sequential manner!

Support for random access to the stream!


Functions to learn current position and seek to new one! 4
Standard I/O Functions!
Portability!
Generic I/O support for C programs!
Specific implementations for various host OSes!
Invokes the OS-specific system calls for I/O!

Abstractions for C programs!


Streams!
Appl Prog
Line-by-line input!
Formatted output !
Stdio Library
user
Additional optimizations!
OS
Buffered I/O! File System
Safe writing!
5
Example: Opening a File !
FILE *fopen("myfile.txt", "r")
Open the named file and return a stream!
Includes a mode, such as r for read or w for write!

Creates a FILE data structure for the file!


Mode, status, buffer, !
Assigns fields and returns a pointer!
Opens or creates the file, based on the mode!
Write (w): create file with default permissions!
Read (r): open the file as read-only!
Append (a): open or create file, and seek to the end!

6
Example: Formatted I/O!
int fprintf(fp1, "Number: %d\n", i)!
Convert and write output to stream in specified format!
int fscanf(fp1, "FooBar: %d", &i)
Read from stream in format and assign converted values!

Specialized versions!
printf() is just fprintf(stdout, )
scanf() is just fscanf(stdin, )

7
Layers of Abstraction!
File descriptor:!
Appl Pgm! An integer that!
User! uniquely identifies!
process! FILE * stream! an open file!
Stdio Library!
int fd!
File System! hierarchical file system!
Operating! Storage! variable-length segments!
System!
Driver! disk blocks!

Disk!

8
System-Level Functions for I/O!
int creat(char *pathname, mode_t mode);
Create a new file named pathname, and return a file descriptor!
int open(char *pathname, int flags, mode_t mode);
Open the file pathname and return a file descriptor!
int close(int fd);
Close fd
int read(int fd, void *buf, int count);
Read up to count bytes from fd into the buffer at buf !!
int write(int fd, void *buf, int count);
Writes up to count bytes into fd from the buffer at buf
int lseek(int fd, int offset, int whence);
Assigns the file pointer of fd to a new value by applying an offset!

9
Example: open()
Converts a path name into a file descriptor!
int open(const char *pathname, int flags,
mode_t mode);
Arguments!
Pathname: name of the file!
Flags: bit flags for O_RDONLY, O_WRONLY, O_RDWR
Mode: permissions to set if file must be created!
Returns!
File descriptor (or a -1 if an error)!
Performs a variety of checks!
E.g., whether the process is entitled to access the file!
Underlies fopen() 10
Example: read()
Reads bytes from a file descriptor!
int read(int fd, void *buf, int count);

Arguments!
File descriptor: integer descriptor returned by open()
Buffer: pointer to memory to store the bytes it reads!
Count: maximum number of bytes to read

Returns!
Number of bytes read!
Value of 0 if nothing more to read!
Value of -1 if an error!

Performs a variety of checks!


Whether file has been opened, whether reading is okay!

Underlies getchar() , fgets(), scanf() , etc.! 11


Example: A Simple getchar()
int getchar(void) {
char c;
if (read(0, &c, 1) == 1)
return c;
else return EOF;
}

Read one character from stdin


File descriptor 0 is stdin
&c points to the buffer!
1 is the number of bytes to read!
Read returns the number of bytes read !
In this case, 1 byte means success! 12
Making getchar() More Efficient!
Poor performance reading one byte at a time!
Read system call is accessing the device (e.g., a disk)!
Reading one byte from disk is very time consuming!
Better to read and write in larger chunks!

Buffered I/O!
Read a large chunk from disk into a buffer!
Dole out bytes to the user process as needed!
Discard buffer contents when the stream is closed!
Similarly, for writing, write individual bytes to a buffer!
And write to disk when full, or when stream is closed!
Known as flushing the buffer!
13
Better getchar() with Buffered I/O!

int getchar(void) {
static char base[1024];
static char *ptr; persistent variables
static int cnt = 0;

if (cnt--) return *ptr++; base

cnt = read(0, base, sizeof(base));


if (cnt <= 0) return EOF;
ptr = base; ptr
return getchar();
}

But, many functions may read (or write) the stream 14


Details of FILE in stdio.h (K&R 8.5)!
#define OPEN_MAX 20 /* max files open at once */

typedef struct _iobuf {


int cnt; /* num chars left in buffer */
char *ptr; /* ptr to next char in buffer */
char *base; /* beginning of buffer */
int flag; /* open mode flags, etc. */
char fd; /* file descriptor */
} FILE;
extern FILE _iob[OPEN_MAX];

#define stdin (&_iob[0])


#define stdout (&_iob[1])
#define stderr (&_iob[2])
15
A Funny Thing About Buffered I/O!
The standard library also buffers output; example:!
int main(void) {
printf("Step 1\n");
sleep(10);
printf("Step 2\n");
return 0;
}

Run a.out > out.txt & and then tail -f out.txt!


To run a.out in the background, outputting to out.txt
And then to see the contents on out.txt
Neither line appears till ten seconds have elapsed!
Because the output is being buffered!
Add fflush(stdout) to flush the output buffer!
fclose() also flushes the buffer before closing! 16
Summary on I/O Management!
System-level I/O functions provide abstractions!
Stream as a source or destination of data!
Functions for manipulating streams!

Standard I/O library builds on these abstractions!


Calls system-level functions for low-level I/O !
Adds buffering!

Powerful examples of abstraction!


Applications interact with streams at a high level!
Standard I/O library interact with streams at lower level!
Only the OS deals with the device-specific details!

17
Process Management!

18
Goals of this Lecture: Processes!
Help you learn about:!
Creating new processes!
Programmatically redirecting stdin, stdout, and stderr!
(Appendix) communication between processes via pipes!

Why?!
Creating new processes and programmatic redirection
are fundamental tasks of a Unix shell (Assignment 7)!

19
Why Create a New Process?!
Run a new program!
E.g., shell executing a program entered at command line!
Or, even running an entire pipeline of commands!
Such as wc l * | sort | uniq -c | sort nr!

Run a new thread of control for the same program!


E.g., a Web server handling a new Web request!
While continuing to allow more requests to arrive!
Essentially time sharing the computer!

Underlying mechanism!
A process executes fork() to create a child process!
(Optionally) child does exec() of a new program!
20
Creating a New Process!
Cloning an existing process!
Parent process creates a new child process!
The two processes then run concurrently ! parent

Child process inherits state from parent !


Identical (but separate) copy of virtual
address space!
Copy of the parents open file descriptors!
Parent and child share access to open files!

Child then runs independently!


Executing independently, including invoking a
new program!
Reading and writing its own address space! child

21
Fork System-Level Function!
fork() is called once!
But returns twice, once in each process!

Telling which process is which !


Parent: fork() returns the childs process ID!
Child: fork() returns 0!
pid = fork();
if (pid != 0) {
/* in parent */

} else {
/* in child */

}
22
Fork and Process State!
Inherited! Separate in child!
User and group IDs! Process ID!
Signal handling settings! Address space (memory)!
Stdio! File descriptors!
File pointers! Parent process ID!
Root directory! Pending signals!
File mode creation mask! Time signal reset times!
Resource limits! !
Controlling terminal!
All machine register
states!
Control register(s)!
! 23
Example: What Output?!
int main(void)
{
pid_t pid;
int x = 1;

pid = fork();
if (pid != 0) {
printf("parent: x = %d\n", --x);
exit(0);
} else {
printf("child: x = %d\n", ++x);
exit(0);
}
} 24
Executing a New Program!
fork() copies the state of the parent process!
Child continues running the parent program!
with a copy of the process memory and registers!

Need a way to invoke a new program!


In the context of the newly-created child process!

Example! NULL-terminated array!


Contains command-line arguments
program!
(to become argv[] of ls)!

execvp("ls", argv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); 25
Waiting for the Child to Finish!
Parent should wait for children to finish!
Example: a shell waiting for operations to complete!

Waiting for a child to terminate: wait()


Blocks until some child terminates!
Returns the process ID of the child process!
Or returns -1 if no children exist (i.e., already exited)!

Waiting for specific child to terminate: waitpid()


Blocks till a child with particular process ID terminates!
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
26
Example: A Simple Shell!
Shell is the parent process!
E.g., bash! bash!
Parses command line!
E.g., ls l!
fork!
Invokes child process!
child! parent!
fork(), execvp()

Waits for child! execvp! wait!


wait()

ls!
27
Simple Shell Code!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) {
/* in child */
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous 28
Simple Shell Trace (1)!
Parent Process!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) {
/* in child */
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous

Parent reads and parses command line!


Parent assigns values to somepgm and someargv

29
Simple Shell Trace (2)!
Parent Process! Child Process!
Parse command line Parse command line
Assign values to somepgm, someargv Assign values to somefile, someargv
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {

concurrently!
/* in child */ /* in child */

executing!
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);
Repeat the previous Repeat the previous

fork() creates child process!


Which process gets the CPU first? Lets assume the parent!

30
Simple Shell Trace (3)!
Parent Process! childs pid! Child Process!
Parse command line Parse command line
Assign values to somepgm, someargv Assign values to somefile, someargv
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {

concurrently!
/* in child */ /* in child */

executing!
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);
Repeat the previous Repeat the previous

In parent, pid != 0; parent waits; OS gives CPU to child!

31
Simple Shell Trace (4)!
Parent Process! 0! Child Process!
Parse command line Parse command line
Assign values to somepgm, someargv Assign values to somefile, someargv
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {

concurrently!
/* in child */ /* in child */

executing!
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);
Repeat the previous Repeat the previous

In child, pid == 0; child calls execvp()


32
Simple Shell Trace (5)!
Parent Process! Child Process!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) { somepgm

concurrently!
/* in child */

executing!
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous

In child, somepgm overwrites shell program;!


main() is called with someargv as argv parameter!
33
Simple Shell Trace (6)!
Parent Process! Child Process!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) { somepgm

concurrently!
/* in child */

executing!
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous

Somepgm executes in child, and eventually exits!


34
Simple Shell Trace (7)!
Parent Process!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) {
/* in child */
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous

Parent returns from wait() and proceeds!


35
Combined Fork/Exec/Wait!
Common combination of operations!
fork() to create a new child process!
exec() to invoke new program in child process!
wait() in the parent process for the child to complete!

Single call that combines all three!


int system(const char *cmd);

Example!

int main(void) {
system("echo Hello world");
return 0;
}
36
Fork and Virtual Memory!
Incidentally!
Question:!
fork() duplicates an entire process (text, bss, data,
rodata, stack, heap sections)!
Isnt that very inefficient???!!!!
Answer:!
Using virtual memory, not really!!
Upon fork(), OS creates virtual pages for child
process!
Each child virtual page points to real page (in memory or
on disk) of parent!
OS duplicates real pages incrementally, and only if/when
write occurs!
37
Redirection!
Unix allows redirection of stdin, stdout, or stderr!
How?!
Use open(), creat(), and close() system calls!
Described in I/O Management lecture!
Use dup() system call!

int dup(int oldfd);


Create a copy of the file descriptor oldfd. After a successful
return from dup() or dup2(), the old and new file descriptors may
be used interchangeably. They refer to the same open file
description and thus share file offset and file status flags. Uses
the lowest-numbered unused descriptor for the new descriptor.
Return the new descriptor, or -1 if an error occurred.!

38
Redirection Example!
How does shell implement somepgm > somefile?!

pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640);
close(1);
dup(fd);
close(fd);
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
39
Redirection Example Trace (1)!
Parent Process! /dev/tty!
0!
File! 1!
descriptor! 2!
table! 3!

pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640);
close(1);
dup(fd);
close(fd);
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);

Parent has file descriptor table; first three point to terminal!


40
Redirection Example Trace (2)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! 3! table!

pid = fork(); pid = fork();


if (pid == 0) { if (pid == 0) {
/* in child */ /* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Parent forks child; child has identical file descriptor table! 41


Redirection Example Trace (3)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! 3! table!

pid = fork(); pid = fork();


if (pid == 0) { if (pid == 0) {
/* in child */ /* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Lets say parent gets CPU first; parent waits! 42


Redirection Example Trace (4)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! somefile! 3! table!

pid = fork(); pid = fork();


if (pid == 0) {
/* in child */
3! if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Child gets CPU; child creates somefile! 43


Redirection Example Trace (5)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! somefile! 3! table!

pid = fork(); pid = fork();


if (pid == 0) {
/* in child */
3! if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Child closes file descriptor 1 (stdout)! 44


Redirection Example Trace (6)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! somefile! 3! table!

pid = fork(); pid = fork();


if (pid == 0) {
/* in child */
3! if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Child duplicates file descriptor 3 into first unused spot! 45


Redirection Example Trace (7)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! somefile! 3! table!

pid = fork(); pid = fork();


if (pid == 0) {
/* in child */
3! if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Child closes file descriptor 3! 46


Redirection Example Trace (8)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! somefile! 3! table!

pid = fork(); pid = fork();


if (pid == 0) {
/* in child */
3! if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); fd = creat("somefile", 0640);
close(1); close(1);
dup(fd); dup(fd);
close(fd); close(fd);
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);

Child calls execvp()! 47


Redirection Example Trace (9)!
Parent Process! /dev/tty! Child Process!
0! 0!
File! 1! 1! File!
descriptor! 2! 2! descriptor!
table! 3! somefile! 3! table!

pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); somepgm
close(1);
dup(fd);
close(fd);
execvp(somepfm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);

Somepgm executes with stdout redirected to somefile! 48


Redirection Example Trace (10)!
Parent Process! /dev/tty!
0!
File! 1!
descriptor! 2!
table! 3!

pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640);
close(1);
dup(fd);
close(fd);
execvp(somefile, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);

Somepgm exits; parent returns from wait() and proceeds!49


The Beginnings of a Unix Shell!

A shell is mostly a big loop!


Parse command line from stdin!
Expand wildcards (*)!
Interpret redirections (<, and >)!
fork(), dup(), exec(), and wait(), as necessary!

Start from the code in earlier slides!


And edit till it becomes a Unix shell!
This is the heart of the last programming assignment!

50
Summary!
System-level functions for creating processes!
fork(): process creates a new child process!
wait(): parent waits for child process to complete!
exec(): child starts running a new program!
system(): combines fork, wait, and exec all in one!

System-level functions for redirection!


open() / creat(): to open a file descriptor!
close(): to close a file descriptor!
dup(): to duplicate a file descriptor!

51
Appendix!

Inter-Process Communication (IPC)!

52
IPC!

different machines

same machine 53
IPC Mechanisms!
Pipes!
Processes on the same machine!
Allows parent process to communicate with child process!
Allows two sibling processes to communicate!
Used mostly for a pipeline of filters!

Sockets (see COS 461)!


Processes on any machines!
Processes created independently!
Used for client/server communication (e.g., Web)!

Both provide abstraction of an ordered stream of bytes


54
Pipes!

55
Example Use of Pipes!
Compute a histogram of content types in my e-mail!
Many e-mail messages, consisting of many lines!
Lines like Content-Type: image/jpeg indicate the type!

Pipeline of Unix commands!


Identifying content type: grep -i Content-Type * !
Extracting just the type: cut -d" " -f2
Sorting the list of types: sort
Counting the unique types: uniq -c !
Sorting the counts: sort nr

Simply running this at the shell prompt:!


grep -i Content-Type * | cut -d" " -f2 | sort |
uniq -c | sort nr!
56
Creating a Pipe!

57
Pipe Example!

child

parent

58
Pipes and Stdio!

child makes stdin (0)


the read side of the pipe

parent makes stdout (1)


the write side of the pipe

59
Pipes and Exec!
child process

invokes a new program

60

You might also like