shell重定向小记

对于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


每一个终端都对应/dev/pts下面的一个文件,向对应的文件写入数据,那么将会显示在我们的终端上面,也可以和别的用户打招呼,如果你sudo的话:

$ 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



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值