unix/linux編程實踐教程:I/O重定向和管道

1. 經典的shell編程

    監視其他用戶的登陸和註銷

#!/bin/sh
who | sort > prev
while true;do
        sleep 10
        who | sort > curr
        echo "logged out:"
        comm -23 prev curr
        echo "logged in:"
        comm -13 prev curr
        mv curr prev
done    
    這裏解釋一下unix的工具comm,可以找出兩個文件中共有的行。比較兩個文件可以得到三個子集:僅文件1有的行,僅文件2有的行,兩者共有的行。

程序輸出:(我通過root用戶運行終端,通過另一個用戶登陸另一個終端,然後退出,程序顯示如下)

root@ThinkPad-T430i:/home/leichaojian# vim watch.sh
root@ThinkPad-T430i:/home/leichaojian# sh watch.sh
logged out:
logged in:
leichaojian pts/9        2014-09-02 19:36 (:0)
logged out:
leichaojian pts/9        2014-09-02 19:36 (:0)
logged in:
^C

2. 經典重定向輸出

#include <stdio.h>

int main( int ac, char *av[] )
{
        int     i;
        printf("number of args:%d, args are:\n", ac);
        for ( i = 0; i < ac; i++ ){
                printf("args[%d] %s\n", i, av[ i ] );
        }
        fprintf(stderr, "this message is sent to stderr.\n");

        return 0;
}
程序運行結果:

leichaojian@ThinkPad-T430i:~$ ./a.out testing > xyz one two 2> oop
leichaojian@ThinkPad-T430i:~$ cat xyz
number of args:4, args are:
args[0] ./a.out
args[1] testing
args[2] one
args[3] two
leichaojian@ThinkPad-T430i:~$ cat oop
this message is sent to stderr.
    這裏> xyz的位置倒不重要,中間也可以有空格符等。但是2代表的是stderr流,中間不能有空格。所以2和>的中間一定沒有空格。

3. 將文件重定向到stdin和stdout


<span style="color:#000000;">#include <stdio.h>
#include <fcntl.h>

int main( void )
{
        int     fd;
        char    line[ 100 ];
        int     newfd;

        fgets( line, 100, stdin ); printf("%s", line );
        fgets( line, 100, stdin ); printf("%s", line );
        fgets( line, 100, stdin ); printf("%s", line );

        fd = open("/etc/passwd", O_RDONLY);
#ifdef CLOSE_DUP
        close( 0 );
        newfd = dup( fd );
#else
        newfd = dup2( fd, 0 );
#endif
        if ( newfd != 0 ){
                fprintf(stderr, "could not open data as fd 0\n");
                exit( 1 );
        }
        close( fd );
        fgets( line, 100, stdin ); printf("%s", line );
        fgets( line, 100, stdin ); printf("%s", line );
        fgets( line, 100, stdin ); printf("%s", line );

        return 0;
}</span>

    程序輸出:

leichaojian@ThinkPad-T430i:~$ ./a.out
hello world
hello world
i love this world
i love this world
and i love unix too
and i love unix too
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

    將文件重定向到stdout:who > userlist。 shell使用進程通過fork產生子進程與子進程調用exec之間的時間間隔來重定向標準輸入,輸出到文件:

#include <stdio.h>
#include <fcntl.h>
int main( void )
{
        int     pid;
        int     fd;
        printf("about to run who into a file\n");

        if ( ( pid = fork() ) == -1 ){
                perror("fork");
                exit(1);
        }
        if ( pid == 0 ){
                close( 1 );
                fd = open("userlist", O_WRONLY | O_CREAT | O_TRUNC, 0644);
                execlp("who","who",NULL);
                perror("execlp");
                exit(1);
        }
        if ( pid != 0 ){
                wait( NULL );
                printf("done running who. results in userlist\n");
        }

        return 0;
}
    程序輸出:

leichaojian@ThinkPad-T430i:~$ ./a.out
about to run who into a file
done running who. results in userlist
leichaojian@ThinkPad-T430i:~$ cat userlist
leichaojian :0           2014-09-02 19:25 (:0)
leichaojian pts/0        2014-09-02 19:33 (:0)

4. 管道編程

    在使用pipe函數的時候,pipe[1]爲寫入端,pipe[0]爲讀取端。以下程序從標準輸入中讀取數據,寫入pipe[1],然後從pipe[0]讀取數據,寫出到標準輸出端。

#include <stdio.h>
#include <unistd.h>

int main( void )
{
        int     len, i, apipe[ 2 ];
        char    buf[ BUFSIZ ];

        if ( pipe( apipe ) == -1 ){
                perror("could not make pipe\n");
                exit( 1 );
        }
        printf("got a pipe! it is file descriptors:{%d %d}\n", apipe[ 0 ], apipe[ 1 ] );
        while ( fgets( buf, BUFSIZ, stdin ) ){
                len = strlen( buf );
                if ( write( apipe[ 1 ], buf, len ) != len ){
                        perror("writing to pipe\n");
                        break;
                }
                for ( i = 0; i < len; i++ )
                        buf[ i ] = 'X';
                len = read( apipe[ 0 ], buf, BUFSIZ );
                if ( len == -1 ){
                        perror( "reading from pipe" );
                        break;
                }
                if ( write( 1, buf, len ) != len ){
                        perror("writing to stdout\n");
                        break;
                }

        }

        return 0;
}
    程序輸出:

leichaojian@ThinkPad-T430i:~$ ./a.out
got a pipe! it is file descriptors:{3 4}
hello world
hello world
i love thisworld
i love thisworld
and i love unix too
and i love unix too
^C

    我們可以使用fork來共享管道(父子進程共用一個管道):

#include <stdio.h>

#define CHILD_MESS "I want a cookie\n"
#define PAR_MESS "testing..\n"
#define oops(m, x) {perror(m);exit(x);}
int main( void )
{
        int     pipefd[ 2 ];
        int     len;
        char    buf[ BUFSIZ ];
        int     read_len;

        if ( pipe( pipefd ) == -1 )
                oops("cannot get a pipe", 1 );

        switch( fork() ){
                case -1:
                        oops("cannot fork.", 2);
                case 0:
                        len = strlen( CHILD_MESS);
                        while ( 1 ){
                                if ( write( pipefd[ 1 ], CHILD_MESS, len ) != len )
                                        oops("write", 3);
                                sleep(5);
                        }
                default:
                        len = strlen(PAR_MESS);
                        while ( 1 ){
                                if ( write(pipefd[1], PAR_MESS, len ) != len )
                                        oops("write", 4);
                                sleep(1);
                                read_len = read( pipefd[0], buf, BUFSIZ);
                                if ( read_len <= 0 )
                                        break;
                                write( 1, buf, read_len );
                        }
        }

        return 0;
}
    程序輸出:

leichaojian@ThinkPad-T430i:~$ ./a.out
testing..
I want a cookie
testing..
testing..
testing..
testing..
I want a cookie
testing..
testing..


    如何實現:pipe who sort這樣的命令?流程如下:

who--->stdin--->(dup)--->pipe[1]--->pipe[0]--->(dup)--->stdin--->sort

#include <stdio.h>
#include <unistd.h>

#define oops(m,x) {perror(m);exit(x);}

int main( int ac, char **av )
{
	int	thepipe[2];
	int	newfd;
	int	pid;

	if ( ac != 3 ){
		fprintf(stderr, "usage:pipe cmd1 cmd2\n");
		exit(1);
	}
	if ( pipe( thepipe ) == -1 )
		oops("cannot get a pipe\n", 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(av[2], av[2], NULL);
		oops(av[2],4);
	}

	close(thepipe[0]);
	if ( dup2(thepipe[1],1) == -1 )
		oops("could not redirect stdout",4);
	close(thepipe[1]);
	execlp(av[1], av[1], NULL);
	oops(av[1],5);

	return 0;
}
    程序輸出:

leichaojian@ThinkPad-T430i:~$ ./a.out who sort
leichaojian :0           2014-09-02 20:42 (:0)
leichaojian pts/0        2014-09-02 20:44 (:0)

對於各種函數的解釋,極力推薦APUE

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章