ILD

shell重定向
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2019-7-23 站点:Inside Linux Development

1 简述

重定向可以允许命令的文件句柄被复制、打开、关闭、指向不同的文件。重定向也可以改变当前shell执行环境的文件句柄。重定向可以出现在命令前,单个命令中的任何地方,或者命令后。重定向按它们出现的顺序从左到右处理。

2 实现重定向的系统调用

open,打开文件,根据重定向的类型,使用对应的只读、只写、读写、追加等标志。


dup2(oldfd, newfd)

执行成功后,新旧文件描述后都可以使用,它们内部指向同一个打开的文件描述,它们分享offset、file status flag等。但是它们不分享file descriptor flags (例如close-on-exec flag)。如果newfd以前已经被打开,那么关闭它。关闭和dup是原子操作。


fcntl(oldfd, F_DUPFD, min_new_fd)

和dup2类似,它复制一个fd,但是使用大于等于min_new_fd的未被占用用的文件描述符。


close,关闭文件描述符。


3 文件重定向

打开文件,然后复制到一个文件描述符,在关闭打开的旧描述符。重定向的方向通过打开的flag实现。


如果打开或创建文件失败,则会导致重定向失败。


3.1 重定向输入 redirecting input

[n]<word

如果省略n,则默认为0(stdin),实现方法:

1
2
3
4
5
6
7
8
open("test", O_RDONLY)                  = 3
fcntl(0, F_GETFD)                       = 0
fcntl(0, F_DUPFD, 10)                   = 10
fcntl(0, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 0)                              = 0
close(3)                                = 0
close(10)                               = 0

只读方式打开文件,然后将要重定向的fd复制一份到最小10(目的是啥呢?),然后复制打开的文件描述符到要重定向的fd,然后关闭打开的文件描述,和之前复制的重定向fd。


3.2 重定向输出 redirecting output

[n]>[|]word

如果没有指定n,则为1(stdout),如果文件不存在则会被创建,如果存在,则会被截断为0。| 影响noclobber选项。实现方法:

1
2
3
4
5
6
7
8
open("test.b", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
close(10)                               = 0

可以看出除了打开文件的flag不同外,它和重定向输入的实现方式是完全一样的。它以只写、创建、截断3个标志打开重定向文件。


3.3 追加重定向输出 Appending redirected output

[n]>>word

同上述两者一样,只不过打开方式变成追加:

1
open("test.b", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3


3.4 重定向标准输出和标准错误到同一个文件 redirecting stdout and stderr

语法

&>word

或者

>&word

如果文件名是数字,不能使用第二种形式。上述等价于 >word 2>&1,实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
open("test.b", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
fcntl(2, F_DUPFD, 10)                   = 11
fcntl(2, F_GETFD)                       = 0
fcntl(11, F_SETFD, FD_CLOEXEC)          = 0
dup2(1, 2)                              = 2
close(11)                               = 0
close(10)                               = 0


3.5 Appending stdout and stderr

语法:

&>>word

等价于 >> word 2>&1


3.6 以读写方式打开文件

[n] <> word


4 Here重定向

重定向的内容来自shell脚本源码。

4.1 Here documents

这种类型的重定向,shell从当前源码读取内容直到包含特定分界符的行,把它们作为命令的标准输入(或特定文件描述符n),语法:

[n]<<[-]word

    here document

delimiter


word不执行任何扩展。

如果word被quoted,则delimiter是word移除quote的结果。here document不执行任何扩展。

1
2
3
4
5
6
7
8
9
10
cat test.sh
#!/bin/bash
 
a=1
cat << "EOF"
    ${a}
EOF
 
$ ./test.sh
    ${a}

如上EOF被引用了,所以here document没有被扩展。


如果word没有被引号括起来,则here ducoment会执行parameter expansion,command substitution,arithmetic expansion,扩展中的\newline被忽略,而 \ $ ' 必须使用\来转义。


如果重定向符是<<-,那么所有行(包括delimiter)的开始的tab字符都被忽略。


4.2 Here strings

here document的一个变种,格式:

[n] <<< word

word会执行brace expansion, tilde expansion, parameter and variable expansion,command substitution, arithmetic expansion, and quote removal。


不执行pathname expansion和word splitting。


结果是一个single string,shell会追加一个newline。


5 Duplicating / Closing file descriptors

两种

[n]<&word

[n]>&word

执行dup2(word, n)


这两者唯一的不同是,当n省略时,<&默认为标准输入(0),>&默认为标准输出。


当word是-时,文件描述符n被关闭。


当n被省略,word既不是数字也不是-

则是一种特殊情况,上面3.4所述,将标准输出和标准错误重定向到文件word。


6 Moving File descriptors

两种形式

[n]<&digit-

[n]>&digit-

复制digit到n,然后关闭digit


8 改变当前shell的文件描述符

将重定向作用到exec命令上

exec

If no command is specified, redirections may be used to affect the current shell environment



参考

bash manual. 3.6 Redirections

Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.