对于int型的,使用open,write,read,close操作,对于FILE*型的使用fopen,fwrite,fread,fclose操作
标准输入,int fd = 0,int fd = STDIN_FILENO,FILE *f = stdin,shell重定向标准输入使用"<",比如./hello <words.txt,那么hello可以从fd=0或者f=stdin里面读取words.txt文件中的内容,平时都是./hello words.txt这样,可以从argv[1]中读取文件名,然后再open/read/close。
有种特殊的情况是这样的,不一定需要使用EOF,任意单词都可以,首尾相同:
$ cat <<EOF > hello > world > EOF hello world $ cat >tmp <<EOF hello world EOF $ cat tmp hello world
有些程序可以接收参数"-",表示从标准输入中读取文件内容
标准输出,int fd = 1,int fd = STDOUT_FILENO,FILE *f = stdout,shell重定向标准输出使用">"(覆盖方式),或者">>"(append方式),">"和">>"前面的默认数字是"1",比如:
$ echo hello 1> tmp $ echo world > tmp $ cat tmp world $ echo hello >>tmp $ echo world >>tmp $ cat tmp world hello world
错误输出,int fd = 2,int fd = STDERR_FILENO,FILE *f = stderr,shell重定向错误输出使用"2>"(覆盖方式),或者"2>>"(append方式),和标准输出类似,注意使用">"对错误输出无效:
$ cat <<EOF >x.c > #include <stdio.h> > int main(void) > { > write(2,"hello world\n",12); > return 0; > } > EOF $ gcc -o x x.c $ ./x >tmp hello world $ ./x 2>tmp $ ./x 2>tmp $ cat tmp hello world $ ./x 2>>tmp $ cat tmp hello world hello world并不一定是2这个数字,而是指错误输出,例如:
$ cat <<EOF >x.c > #include <stdio.h> > #include <unistd.h> > int main() > { > int fd = dup(2); > write(fd,"hello world\n",12); > return 0; > } > EOF $ gcc -o x x.c $ ./x >/dev/null 2>&1 $
有时候常用到"2>&1"这种,是将错误输出重定向到标准输出,为什么要加"&"呢,因为不加就会重定向到一个名为"1"的文件
如果标准输出和错误输出都需要重定向,那么应该先写标准输出的,再写错误输出的:
$ ./x 2>&1 >/dev/null hello world $ ./x >/dev/null 2>&1 $/dev/null就是个垃圾桶,扔进去的都没了,类似还有/dev/zero,从里面可以读出来无数的0
shell 使用"|"将上一条命令的标准输出,作为下一条命令的标准输入,例如:
$ cat x.c #include <stdio.h> int main(void) { write(2,"hello world\n",12); return 0; } $ cat x.c | grep return return 0;
可以使用proc看到每个进程打开了多少fd,以及fd打开的是谁(self可以替换为具体的pid):
$ cd /proc/self/fd $ ls -l total 0 lrwx------ 1 xxxxxx users 64 Mar 7 22:31 0 -> /dev/pts/0 lrwx------ 1 xxxxxx users 64 Mar 7 22:31 1 -> /dev/pts/0 lrwx------ 1 xxxxxx users 64 Mar 7 22:31 2 -> /dev/pts/0 lrwx------ 1 xxxxxx users 64 Mar 7 22:46 255 -> /dev/pts/0
$ cd /dev/pts/ $ ls -l total 0 crw--w---- 1 xxxxxx tty 136, 0 Mar 7 23:21 0 crw--w---- 1 root tty 136, 12 May 27 2015 12 crw--w---- 1 root tty 136, 9 May 18 2015 9 $ echo hello >0 hello
还有个比较有意思的就是pipe文件,注意ls -l显示出的文件类型为"p":
$ mkfifo mypipe $ ls -l mypipe prw-r--r-- 1 xxxxxx users 0 Mar 7 23:24 mypipe
可以一个进程将输出写到mypipe,另一个进程从mypipe文件读取第一个进程输出的内容,
甚至可以这样玩,先在一个终端上启动nc服务器:
tree@iZ28dbdyyxuZ:~$ nc -lvnp 8888 Listening on [0.0.0.0] (family 0, port 8888) Connection from [127.0.0.1] port 8888 [tcp/*] accepted (family 2, sport 55010)另一个终端使用pipe文件,将bash的标准输出给nc的标准输入,nc的标准输出给bash的标准输入:
/bin/bash <mypipe | nc localhost 8888 >mypipe
这样的话,就可以在第一个终端,输入shell命令了,控制了第二个终端所在的机器
关于time,你没法重定向time的输出:
$ time ls log mypipe x x.c real 0m0.002s user 0m0.000s sys 0m0.000s $ time ls >/dev/null 2>&1 real 0m0.002s user 0m0.000s sys 0m0.000s
因为time是shell builtin的命令,重定向是由shell自己来处理的,使用time命令的时候,重定向的东西被当做普通参数了。所以time得到的argv={"ls", ">/dev/null", "2>&1"},而不是{"ls"}
如果是普通的程序,比如/usr/bin/time,重定向的东西就是重定向,没法被当做普通参数,所以/usr/bin/time可以被重定向掉:
$ /usr/bin/time ls log mypipe x x.c 0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 3840maxresident)k 0inputs+0outputs (0major+298minor)pagefaults 0swaps $ /usr/bin/time ls >/dev/null 0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 3840maxresident)k 0inputs+0outputs (0major+298minor)pagefaults 0swaps $ /usr/bin/time ls >/dev/null 2>&1