so true

心怀未来,开创未来!
随笔 - 160, 文章 - 0, 评论 - 40, 引用 - 0
数据加载中……

bash redirect re-study

本质:先理解linux里的int dup2(int oldfd, int newfd)命令,dup2() makes newfd be the copy of oldfd。
理解:重定向这个概念其实不是很好理解,如果用编程里面的指针来说明,那就很容易了。举个例子,比如指针p1指向瓶子,指针p2指向抽屉,现在执行p1>&p2(相当于p1 = p2),这样p1这个指针也指向抽屉了,也就是说我们把p1这个指针重定向到一个新的地方,这个地方是p2所指的地方,即抽屉;
    简而言之,这个例子里重定向的含义是:把p1指向p2所指的地方(重定向就是指向的含义),而瓶子、抽屉这2个“实体”是不变的,重定向能调整的只是指针的指向。
    $ ls -l /proc/$$/fd
    lr-x------ 1 admin admin 64 2016-03-30 10:14 0 -> /dev/pts/413
    lrwx------ 1 admin admin 64 2016-03-30 10:14 1 -> /dev/pts/413
    lrwx------ 1 admin admin 64 2016-03-30 10:14 2 -> /dev/pts/413
    lrwx------ 1 admin admin 64 2016-03-30 10:14 255 -> /dev/pts/413
    我们说0代表stdin,1代表stdout,2代表stderr,这里stdin/stdout/stderr是实体(这里都是/dev/pts/413,即terminal这个设备),0/1/2只是一个fd,可以理解为指针或者标记;
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) 2>&1 >file1之所以file1里只会有1行,原因是:
    我们首先把2指向了stdout(stdout正是1所指的东西),这个时候1和2都指向了stdout;
    然后我们把1指向了file1,这个时候2依然还是指着stdout;
    然后I'm from stdout这句话写到了1里面,其实也就是写到了file1里面,I'm from stderr这句话写到了2里面,其实也就是写到了stdout里面。
整体规则:
    1. TO (<|>|<>) FROM;
    2. (<|>)这两个东西后面可以跟&fd/&-/&fd-,也可以跟一个file名字;例外>&file1表示stdout和stderr都重定向到file1里面;<>后面只可以跟file1,例如<>file1表示从file1里既读入数据,也写入数据;
    3. (<|>|<>)这三个东西前面不能有空格,后面跟的&不能有空格,除此之外无要求,例如:exec 1>& 2- #但2和-之间不能有空格;
操作:
    1. 打开一个fd的方法:exec fd>&1  或者   exec fd<&0 或者 exec fd>file1 或者 exec fd<file1 或者 exec fd <>file1;
       如果你不想指定fd(希望系统自动给你分配一个fd),那么有一种特殊的用法,例子是:
         exec {NEW_STDOUT}>&1 #注意这个用法很特殊,你不能NEW_STDOUT=15; exec ${NEW_STDOUT}>&1
         echo "hello" >&$NEW_STDOUT # echo "hello" >&${NEW_STDOUT}也可以
         echo ${NEW_STDOUT} #从10开始分配
         exec {NEW_STDOUT}>&-
    2. 关闭一个fd的方法:exec fd>&- 或者 exec fd<&-
    3. move fd的方法:new_fd>&old_fd-,move完之后,old_fd会被关掉;
实战:
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) 2>&1 >file1 #file1里将会有1行I'm from stdout,原因是stdout赋给了stderr,file1赋给了stdout,2句话里,打印到stdout的那句被写入file1,打印到stderr被写入到了stdout
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) >file1 2>&1 #file1里将会有2行,原因是file1赋给了stdout,stdout赋给了stderr(其实也就是file1赋给了stderr),这个时候,stdout和stderr都指向了file1
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) &> file1 #file1里将会有2行,file1前面的空格可以省略
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) >& file1 #file1里将会有2行,file1前面的空格可以省略
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) |& cat > file1 #file1里将会有2行,file1前面的空格可以省略
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) 2>&1 | cat > file1 #file1里将会有2行,file1前面的空格可以省略
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) >file1 | grep err #grep fail
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) 2>&1 >file1 | grep err #grep ok
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) 3>&1 1>&2 2>&3-| grep stderr #grep ok,这其实实现了stdout和stderr的交换,类似于通过c=a;a=b;b=c;来实现a和b的交换(先把a赋给c,紧接着找到b赋给a,然后用c再赋给b)
    (echo "I'm from stdout"; echo "I'm from stderr" 1>&2) 1>&2- | grep stderr #grep ok
    echo "hello world" | tee >(grep hello) >(grep world) >/dev/null #结合上tee的多路dispatch,功能会更强大
    > file1 #create file1 or truncate file1 to zero size
    <file1 cat #<file1这部分放到命令的前面或者后面都可以
    2>&1 ls not_found_file | grep found #grep ok
    cat < file1 > file2 #等同于cp file1 file2
<>高级用法:
    1. 写到一个文件中指定的地方:
        echo 1234567890 > file1   # 写字符串到"File".
        exec 3<> file1            # 打开"File"并且给它分配fd 3.
        read -n 4 <&3             # 只读4个字符.
        echo -n . >&3             # 写一个小数点.
        exec 3>&-                 # 关闭fd 3.
        cat file1                 # ==> 1234.67890
    2. 用bash下载网页
        $ exec 3<>/dev/tcp/www.baidu.com/80
        $ echo -e "GET / HTTP/1.0\r\n\r\n" >&3
        $ cat <&3
        $ ls -l /proc/$$/fd
        total 0
        lr-x------ 1 admin admin 64 2016-03-30 10:14 0 -> /dev/pts/413
        lrwx------ 1 admin admin 64 2016-03-30 10:14 1 -> /dev/pts/413
        lrwx------ 1 admin admin 64 2016-03-30 10:14 2 -> /dev/pts/413
        lrwx------ 1 admin admin 64 2016-03-30 10:14 255 -> /dev/pts/413
        lrwx------ 1 admin admin 64 2016-03-30 10:14 3 -> socket:[173770096]
        $ exec 3>&- # exec 3<&-也可以关闭

posted on 2016-03-30 12:10 so true 阅读(244) 评论(0)  编辑  收藏 所属分类: Linux


只有注册用户登录后才能发表评论。


网站导航: