重定向可以允许命令的文件句柄被复制、打开、关闭、指向不同的文件。重定向也可以改变当前shell执行环境的文件句柄。重定向可以出现在命令前,单个命令中的任何地方,或者命令后。重定向按它们出现的顺序从左到右处理。
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,关闭文件描述符。
打开文件,然后复制到一个文件描述符,在关闭打开的旧描述符。重定向的方向通过打开的flag实现。
如果打开或创建文件失败,则会导致重定向失败。
[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。
[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个标志打开重定向文件。
[n]>>word
同上述两者一样,只不过打开方式变成追加:
1 | open("test.b", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3 |
语法
&>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 |
语法:
&>>word
等价于 >> word 2>&1
[n] <> word
重定向的内容来自shell脚本源码。
这种类型的重定向,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字符都被忽略。
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。
两种
[n]<&word
[n]>&word
执行dup2(word, n)
这两者唯一的不同是,当n省略时,<&默认为标准输入(0),>&默认为标准输出。
当word是-时,文件描述符n被关闭。
当n被省略,word既不是数字也不是-
则是一种特殊情况,上面3.4所述,将标准输出和标准错误重定向到文件word。
两种形式
[n]<&digit-
[n]>&digit-
复制digit到n,然后关闭digit
将重定向作用到exec命令上
exec
If no command is specified, redirections may be used to affect the current shell environment
参考
bash manual. 3.6 Redirections