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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值