Blog

创建输入文件描述符

Content #

在重定向到文件之前,先将STDIN指向的位置保存到另一个文件描述符,然后在读取完文件之后将STDIN恢复到原先的位置:

$ cat test15
#!/bin/bash
# redirecting input file descriptors

exec 6<&0

exec 0< testfile

count=1
while read line
do
   echo "Line #$count: $line"
   count=$[ $count + 1 ]
done
exec 0<&6
read -p "Are you done now? " answer
case $answer in
Y|y) echo "Goodbye";;
N|n) echo "Sorry, this is the end.";;
esac
$ ./test15
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
Are you done now? y
Goodbye
$

在这个例子中,文件描述符6用于保存STDIN指向的位置。然后脚本将STDIN重定向到一个文件。read命令的所有输入都来自重定向后的STDIN(也就是输入文件)。

...

重定向文件描述符

Content #

可以将STDOUT的原先位置重定向到另一个文件描述符,然后再利用该文件描述符恢复STDOUT。

$ cat test14
#!/bin/bash
# storing STDOUT, then coming back to it

exec 3>&1
exec 1>test14out

echo "This should store in the output file"
echo "along with this line."

exec 1>&3

echo "Now things should be back to normal"
$
$ ./test14
Now things should be back to normal
$ cat test14out
This should store in the output file
along with this line.
$

第一个exec命令将文件描述符3重定向到了文件描述符1(STDOUT)的当前位置,也就是显示器。这意味着任何送往文件描述符3的输出都会出现在屏幕上。

...

创建输出文件描述符

Content #

可以用exec命令分配用于输出的文件描述符。和标准的文件描述符一样,一旦将替代性文件描述符指向文件,此重定向就会一直有效,直至重新分配。

$ cat test13
#!/bin/bash
# using an alternative file descriptor

exec 3>test13out

echo "This should display on the monitor"
echo "and this should be stored in the file" >&3
echo "Then this should be back on the monitor"
$ ./test13
This should display on the monitor
Then this should be back on the monitor
$ cat test13out
and this should be stored in the file
$

这个脚本使用exec命令将文件描述符3重定向到了另一个文件。当脚本执行echo 语句时,文本会像预想中那样显示在STDOUT中。但是,重定向到文件描述符3的那行echo语句的输出进入了另一个文件。这样就可以维持显示器的正常输出,并将特定信息重定向到指定文件(比如日志文件)。

...

在脚本中重定向输入

Content #

可以使用与重定向STDOUT和STDERR相同的方法,将STDIN从键盘重定向到其他位置。在Linux系统中,exec命令允许将STDIN重定向为文件:

exec 0< testfile

该命令会告诉shell,它应该从文件testfile中而不是键盘上获取输入。只要脚本需要输入,这个重定向就会起作用。来看一个用法示例:

$ cat test12
#!/bin/bash
# redirecting file input

exec 0< testfile
count=1

while read line
do
   echo "Line #$count: $line"
   count=$[ $count + 1 ]
done
$ ./test12
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
$

将STDIN重定向为文件后,当read命令试图从STDIN读入数据时,就会到文件中而不是键盘上检索数据。

这是一种在脚本中从待处理的文件读取数据的绝妙技术。Linux系统管理员的日常任务之一就是从日志文件中读取并处理数据。这是完成该任务最简单的办法。

From #

Linux命令行与shell脚本编程大全

永久重定向

Content #

如果脚本中有大量数据需要重定向,那么逐条重定向所有的echo语句会很烦琐。这时可以用exec命令,它会告诉shell在脚本执行期间重定向某个特定文件描述符:

$ cat test10
#!/bin/bash
# redirecting all output to a file
exec 1>testout

echo "This is a test of redirecting all output"
echo "from a script to another file."
echo "without having to redirect every individual line"
$ ./test10
$ cat testout
This is a test of redirecting all output
from a script to another file.
without having to redirect every individual line
$

exec命令会启动一个新shell并将STDOUT文件描述符重定向到指定文件。脚本中送往STDOUT的所有输出都会被重定向。

也可以在脚本执行过程中重定向STDOUT:

$ cat test11
#!/bin/bash
# redirecting output to different locations

exec 2>testerror

echo "This is the start of the script"
echo "now redirecting all output to another location"

exec 1>testout

echo "This output should go to the testout file"
echo "but this should go to the testerror file" >&2
$
$ ./test11
This is the start of the script
now redirecting all output to another location
$ cat testout
This output should go to the testout file
$ cat testerror
but this should go to the testerror file
$

该脚本使用exec命令将送往STDERR的输出重定向到了文件testerror。接下来,脚本用echo语句向STDOUT显示了几行文本。随后再次使用exec命令将STDOUT重定向到testout文件。注意,尽管STDOUT被重定向了,仍然可以将echo语句的输出发送给STDERR,在本例中仍是重定向到testerror文件。

...

临时重定向

Content #

如果你有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR。这只需要使用输出重定向符号将输出重定向到STDERR文件描述符。

在重定向到文件描述符时,必须在文件描述符索引值之前加一个&:

echo "This is an error message" >&2

这行会在脚本的STDERR文件描述符所指向的位置显示文本。下面这个例子就使用了这项功能:

$ cat test8
#!/bin/bash
# testing STDERR messages

echo "This is an error" >&2
echo "This is normal output"
$

如果像平常一样运行这个脚本,你看不出任何区别: $ ./test8 This is an error This is normal output $

记住,在默认情况下,STDERR和STDOUT指向的位置是一样的。但是,如果在运行脚本时重定向了STDERR,那么脚本中所有送往STDERR的文本都会被重定向: $ ./test8 2> test9 This is normal output $ cat test9 This is an error $

太好了!通过STDOUT显示的文本出现在了屏幕上,而送往STDERR的echo语句的文本则被重定向到了输出文件。

这种方法非常适合在脚本中生成错误消息。脚本用户可以像上面的例子中那样,直接通过STDERR文件描述符重定向错误消息。

From #

Linux命令行与shell脚本编程大全

特殊的重定向符&>

Content #

可以将STDERR和STDOUT的输出重定向到同一个文件。为此,bash shell提供了特殊的重定向符&>:

$ ls -al test test2 test3 badtest &> test7
$ cat test7
ls: cannot access test: No such file or directory
ls: cannot access badtest: No such file or directory
-rw-rw-r-- 1 rich rich 158 2020-06-20 11:32 test2
-rw-rw-r-- 1 rich rich   0 2020-06-20 11:33 test3
$

当使用&>时,命令生成的所有输出(正常输出和错误消息)会被送往同一位置。

注意,其中一条错误消息出现的顺序和预想不同。badtest文件(列出的最后一个文件)的这条错误消息出现在了输出文件的第二行。

为了避免错误消息散落在输出文件中,相较于标准输出,bash shell自动赋予了错误消息更高的优先级。这样你就能集中浏览错误消息了。

From #

Linux命令行与shell脚本编程大全

sub:输入输出重定向(Bash)

Content #

STDIN文件描述符代表shell的标准输入。对终端界面来说,标准输入就是键盘。 shell会从STDIN文件描述符对应的键盘获得输入并进行处理。

在使用输入重定向符(<)时,Linux会用重定向指定的文件替换标准输入文件描述符。于是,命令就会从文件中读取数据,就好像这些数据是从键盘键入的。

STDOUT文件描述符代表shell的标准输出。在终端界面上,标准输出就是终端显示器。shell的所有输出(包括shell中运行的程序和脚本)会被送往标准输出,也就是显示器。

特殊的重定向符&> 临时重定向 永久重定向 在脚本中重定向输入 创建输出文件描述符 重定向文件描述符 创建输入文件描述符 创建读写文件描述符 关闭文件描述符 列出打开的文件描述符 快速清空文件内容 内联输入重定向(inline input redirection)

read命令读取文件

Content #

每次调用read命令都会从指定文件中读取一行文本。当文件中没有内容可读时, read命令会退出并返回非0退出状态码。

其中麻烦的地方是将文件数据传给read命令。最常见的方法是对文件使用cat命令,将结果通过管道直接传给含有read命令的while命令。来看下面的例子:

$ cat readfile.sh
#!/bin/bash
# Using the read command to read a file
#
count=1
cat $HOME/scripts/test.txt | while read line
do
     echo "Line $count: $line"
     count=$[ $count + 1 ]
done
echo "Finished processing the file."
exit
$
$ cat $HOME/scripts/test.txt
The quick brown dog jumps over the lazy fox.
This is a test. This is only a test.
O Romeo, Romeo! Wherefore art thou Romeo?
$
$ ./readfile.sh
Line 1: The quick brown dog jumps over the lazy fox.
Line 2: This is a test. This is only a test.
Line 3: O Romeo, Romeo! Wherefore art thou Romeo?
Finished processing the file.
$

while循环会持续通过read命令处理文件中的各行,直到read命令以非0退出状态码退出。

...