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