转载地址:http://blog.sina.com.cn/s/blog_87edb138010145ux.html
shell 在执行一个命令时,始终会打开三个文件,标准输入文件(stdin)、标准输出文件(stdout)、标准错误输出文件(stderr)。标准输入文件对应键盘、鼠标等输入设备;标准输出文件和标准错误文件对应显示器等输出设备。shell 启动的进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件。
在类 unix 系统中,系统为每一个打开的文件指定一个文件描述符(file descriptor)以便系统对文件进行跟踪。文件描述符和 c 语言的文件句柄相似,文件描述符是一个非负整数, 不同数字代表不同的含义。默认情况下,系统使用了三个,分别是 0、1、2。而 3 - 9 是保留的文件描述符。
0/1/2 文件描述符和文件的对应关系
| | | |
| | | |
| | | |
| | | |
输入、输出重定向是一个过程,它捕捉一个文件、命令、程序、脚本、或者脚本中的代码块的输出(输入重定向),把捕捉到的输出作为输入发送给另外一个文件、命令、程序、脚本(输出重定向)。
标准输入重定向把文件、命令、程序、脚本的标准输入重定向到指定的文件中。也就是说,输入可以不来自键盘,而来自一个指定的文件。所以说,标准输入重定向主要用于改变一个命令的输入源,特别是改变那些需要大量输入的输入源。
标准输出重定向把文件、命令、程序、脚本的标准输出重定向到指定的文件中。这样就不必输出到显示器,而可以输出到一个指定的文件。
简单的标准输入输出重定向操作
| |
| |
| |
| |
对于标准输出重定向来说,如果文件不存在,则生成文件,并将命令的输出写入到文件中。如果文件存在,> 重定向操作符将命令的输出覆盖文件的原有内容;而 >> 重定向操作符将命令的输出追加到文件的末尾。
示例 1
![shell <wbr>输入输出重定向 shell <wbr>输入输出重定向](https://i-blog.csdnimg.cn/blog_migrate/136e1acc25e723550fb2cbfc6e03ec56.jpeg)
输入输出重定向
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
重定向输入(redirecting input)
输入重定向引起文件(file 进行 shell 展开的结果)以读方式被打开,从文件描述符 n 输入的内容被定向为从文件读入。
语法格式如下:
1 以读方式打开文件,并为文件分配文件描述符 n。
2 如果省略 n,则文件描述符为 0(即标准输入)。
3 注意 < 前后不能有空格;当 n 省略时,< 前后允许有空格。
重定向输出(redirecting output)
输出重定向引起文件(file 进行 shell 展开的结果)以写方式被打开,输出到文件描述符 n 的内容被定向为写入到文件。即重定向文件描述符 n 到文件。
语法格式如下:
1 以写方式打开文件,并为文件分配文件描述符 n。
2 如果省略 n,则文件描述符为 1(即标准输出)。
3 如果文件不存在,则创建文件;否则文件内容将被覆盖。
4 注意 > 前后不能有空格;当 n 省略时,> 前后允许有空格。
追加重定向输出(appending redirected output)
语法格式如下:
1 以追加写方式打开文件,并为文件分配文件描述符 n。
2 >> 和 > 一样,只是向文件写入内容的方式不一样。前者当文件存在时向文件追加内容;后者当文件存在时覆盖文件原有内容。
3 注意 >> 前后不能有空格;当 n 省略时,>> 前后允许有空格。
示例 2
![shell <wbr>输入输出重定向 shell <wbr>输入输出重定向](https://i-blog.csdnimg.cn/blog_migrate/bb6f2db50835af06d5bed73111dcb8f7.jpeg)
重定向标准输出和标准错误输出(redirecting standard output and standard error)
shell 允许标准输出(文件描述符为 1)和标准错误输出(文件描述符为 2)重定向到文件。
语法格式如下:
或者
等同于
1 文件为 file 进行 shell 展开的结果。
2 两种形式在语法上是等同的,但提倡采用第一种方式。
3 如果文件不存在,则创建文件;否则文件内容将被覆盖。
4 &>file 和 >&file 在语法形式等同于 >file 2>&1。
追加重定向标准输出和标准错误输出(appending standard output and standard error)
shell 允许标准输出(文件描述符为 1)和标准错误输出(文件描述符为 2)以追加方式重定向到文件。
语法格式如下:
等同于
1 当文件不存在时,则创建文件;当文件存在时,则向文件追加内容。
示例 3
![shell <wbr>输入输出重定向 shell <wbr>输入输出重定向](https://i-blog.csdnimg.cn/blog_migrate/e7503905fc3da227f84b58b85785b8c5.jpeg)
here documents
这种类型的重定向指示 shell 从当前来源读输入直到出现仅包含 here_limit_string 的一行。
详细描述请参考《shell here 文档》。
语法格式如下:
here strings
字符串(string 进行 shell 展开的结果)作为输入(代替标准输入)提供给命令。
详细描述请参考《shell here 文档》。
语法格式如下:
以读写方式打开文件描述符(opening file descriptors for reading and writing)
输入输出重定向引起文件(file 进行 shell 展开的结果)在指定文件描述符处以读写方式被打开。
语法格式如下:
1 以读写方式打开文件,并为文件分配文件描述符 n。
2 如果省略 n,则文件描述符为 0(即标准输入)。
3 如果文件不存在,则创建文件。
4 实际可以这样理解,为了读写文件,把文件打开,并分配文件描述符 n 给文件。
关闭文件描述符(close file descriptors)
语法格式如下:
1 表示关闭输入文件描述符 n。
2 如果省略 n,则文件描述符为 0(即标准输入)。
语法格式如下:
1 表示关闭输出文件描述符 n。
2 如果省略 n,则文件描述符为 1(即标准输出)。
示例 4
test.sh 文件的内容如下
echo 123456789 > digit.txt
# open file descriptor
exec 3<>digit.txt
read -n 4 <&3
echo -n . >&3
# close file descriptor
exec 3>&-
number=$(cat < digit.txt)
echo number=$number
在命令提示符下输入 ./test.sh,执行结果如下:
number=1234.6789
复制文件描述符(duplicating file descriptors)
shell 允许将一个文件描述符复制到另外一个文件描述符,这样两个文件描述符将指向同一个文件。
语法格式如下:
1 将文件描述符 digit 复制到文件描述符 n(如果省略 n,则文件描述符为 0(即标准输入))。从文件描述符 n 输入都将重定向为从文件描述符 digit 输入。
2 digit 是一个数字。
语法格式如下:
1 将文件描述符 digit 复制到文件描述符 n(如果省略 n,则文件描述符为 1(即标准输出))。输出到文件描述符 n 的内容都将重定向输出到文件描述符 digit。
2 digit 是一个数字。
示例 5
test.sh 文件的内容如下
echo "abc" > 1.txt
echo "def" > 2.txt
# open file descriptor
exec 3<1.txt
exec 4<2.txt
# duplicate file descriptor
exec 3<&4
echo "ghi" >> 2.txt
cat <&3
在命令提示符下输入 ./test.sh,执行结果如下:
def
ghi
示例 6
test.sh 文件的内容如下
echo "abc" > 1.txt
echo "def" > 2.txt
# open file descriptor
exec 3<>1.txt
exec 4<>2.txt
# duplicate file descriptor
exec 3>&4
read -n 2 <&3
echo "ghi" >&3
# close file descriptor
exec 3>&-
exec 4>&-
content1=$(cat 1.txt)
content2=$(cat 2.txt)
echo content1=$content1
echo content2=$content2
在命令提示符下输入 ./test.sh,执行结果如下:
content1=abc
content2=deghi
移动文件描述符(moving file descriptors)
shell 允许将一个文件描述符移动到另外一个文件描述符。
shell 在将一个文件描述符复制到另外一个文件描述符之后,将原来的文件描述符关闭。
语法格式如下:
1 将文件描述符 digit 移动到文件描述符 n(如果省略 n,则文件描述符为 0(即标准输入))。
2 文件描述符将复制到文件描述符 n,之后文件描述符 digit 将关闭。文件描述符 digit 将不能再使用,否则会出错。
3 digit 是一个数字。
语法格式如下:
1 将文件描述符 digit 移动到文件描述符 n(如果省略 n,则文件描述符为 1(即标准输出))。
2 文件描述符将复制到文件描述符 n,之后文件描述符 digit 将关闭。文件描述符 digit 将不能再使用,否则会出错。
3 digit 是一个数字。
示例 7
test.sh 文件的内容如下
echo "abc" > 1.txt
echo "def" > 2.txt
# open file descriptor
exec 3<>1.txt
exec 4<>2.txt
# duplicate file descriptor
exec 3>&4-
read -n 2 <&3
echo "ghi" >&3
read -n 2 <&4
echo "ghi" >&4
content1=$(cat 1.txt)
content2=$(cat 2.txt)
echo content1=$content1
echo content2=$content2
在命令提示符下输入 ./test.sh,执行结果如下:
./test.sh: line 14: 4: wrong file descriptor
./test.sh: line 15: 4: wrong file descriptor
content1=abc
content2=deghi
exec 命令和输入输出重定向
在默认情况下,shell 执行完重定向命令后,会自动 reset(输入、输出将恢复到标准输入、标准输出)。这样下面的命令将不会在进行重定向操作。
shell 提供了 exec 命令,当该命令执行重定向命令后,后边所有的操作(输入和输出),都不会被 reset。也就是说,后边所有的操作都是在重定向的基础上完成的。
exec 重定向标准输入
使用 exec < file,将会使 stdin 重定向到文件中。从这条命令开始,后边所有的输入都来自于文件,而不是标准输入了。
示例 8
test.sh 文件的内容如下
echo abc > 1.txt
echo def >> 1.txt
# save stdin
exec 6<&0
exec < 1.txt
read line1
read line2
# resume stdin and close fd #6
exec 0<&6 6<&-
echo line1=$line1
echo line2=$line2
在命令提示符下输入 ./test.sh,执行结果如下:
line1=abc
line2=def
exec 重定向标准输出
使用 exec > file,将会使 stdout 重定向到文件中。从这条命令开始,后边所有的输出到 stdout 的内容都将输出到文件,而不是标准输出了。
示例 9
test.sh 文件的内容如下
# save stdout
exec 6>&1
exec > 1.txt
# all stdout will output 1.txt
echo abc
echo def
# resume stdout and close fd #6
exec 1>&6 6>&-
content=$(cat 1.txt)
echo content=$content
在命令提示符下输入 ./test.sh,执行结果如下:
content=abc def
使用 exec 命令实现重定向 stdin 和 stdout,从一个文件读入并写入到另外一个文件。
示例 10
test.sh 文件的内容如下
input_file=1.txt
output_file=2.txt
echo 0001 > 1.txt
echo 0010 >> 1.txt
echo 0011 >> 1.txt
# save stdin and input redirect 1.txt
exec 6<&0
exec < 1.txt
# save stdout and output redirect 2.txt
exec 7>&1
exec > 2.txt
read num1
read num2
read num3
echo $((2#${num1} + 1))
echo $((2#${num2} + 2))
echo $((2#${num3} + 3))
# resume stdout and close fd #7
exec 1>&7 7>&-
# resume stdin and close fd #6
exec 0<&6 6<&-
# from here stdin and stdout are normal operate
在命令提示符下输入 ./test.sh,将在当前目录下生成 1.txt 和 2.txt。
在命令提示符下输入 cat 1.txt,执行结果如下:
0001
0010
0011
在命令提示符下输入 cat 2.txt,执行结果如下:
2
4
6
示例 11
test.sh 文件的内容如下
echo 0001 > 1.txt
echo 0010 >> 1.txt
echo 0011 >> 1.txt
exec 3<1.txt
while read <&3
do
done
exec 3<&-
echo 1.txt has $lines line
在命令提示符下输入 ./test.sh,执行结果如下:
1.txt has 3 line