始终有三个默认的 文件 [1] 处于打开状态,stdin(键盘),stdout(屏幕),以及stderr(错误消息输出到屏幕)。这些文件以及任何其他打开的文件都可以被重定向。重定向简单来说就是捕获来自文件、命令、程序、脚本甚至脚本内代码块(参见示例 3-1 和 示例 3-2)的输出,并将其作为输入发送到另一个文件、命令、程序或脚本。
每个打开的文件都会被分配一个文件描述符。[2] 以下的文件描述符分别是stdin, stdout、以及stderr分别为 0、1 和 2。对于打开其他文件,还剩下描述符 3 到 9。有时将这些额外的文件描述符之一分配给stdin, stdout或stderr作为临时的重复链接非常有用。[3] 这简化了在复杂的重定向和重新排列后恢复到正常状态的过程(参见示例 20-1)。
COMMAND_OUTPUT >
# Redirect stdout to a file.
# Creates the file if not present, otherwise overwrites it.
ls -lR > dir-tree.list
# Creates a file containing a listing of the directory tree.
: > filename
# The > truncates file "filename" to zero length.
# If file not present, creates zero-length file (same effect as 'touch').
# The : serves as a dummy placeholder, producing no output.
> filename
# The > truncates file "filename" to zero length.
# If file not present, creates zero-length file (same effect as 'touch').
# (Same result as ": >", above, but this does not work with some shells.)
COMMAND_OUTPUT >>
# Redirect stdout to a file.
# Creates the file if not present, otherwise appends to it.
# Single-line redirection commands (affect only the line they are on):
# --------------------------------------------------------------------
1>filename
# Redirect stdout to file "filename."
1>>filename
# Redirect and append stdout to file "filename."
2>filename
# Redirect stderr to file "filename."
2>>filename
# Redirect and append stderr to file "filename."
&>filename
# Redirect both stdout and stderr to file "filename."
# This operator is now functional, as of Bash 4, final release.
M>N
# "M" is a file descriptor, which defaults to 1, if not explicitly set.
# "N" is a filename.
# File descriptor "M" is redirect to file "N."
M>&N
# "M" is a file descriptor, which defaults to 1, if not set.
# "N" is another file descriptor.
#==============================================================================
# Redirecting stdout, one line at a time.
LOGFILE=script.log
echo "This statement is sent to the log file, \"$LOGFILE\"." 1>$LOGFILE
echo "This statement is appended to \"$LOGFILE\"." 1>>$LOGFILE
echo "This statement is also appended to \"$LOGFILE\"." 1>>$LOGFILE
echo "This statement is echoed to stdout, and will not appear in \"$LOGFILE\"."
# These redirection commands automatically "reset" after each line.
# Redirecting stderr, one line at a time.
ERRORFILE=script.errors
bad_command1 2>$ERRORFILE # Error message sent to $ERRORFILE.
bad_command2 2>>$ERRORFILE # Error message appended to $ERRORFILE.
bad_command3 # Error message echoed to stderr,
#+ and does not appear in $ERRORFILE.
# These redirection commands also automatically "reset" after each line.
#======================================================================= |
2>&1
# Redirects stderr to stdout.
# Error messages get sent to same place as standard output.
>>filename 2>&1
bad_command >>filename 2>&1
# Appends both stdout and stderr to the file "filename" ...
2>&1 | [command(s)]
bad_command 2>&1 | awk '{print $5}' # found
# Sends stderr through a pipe.
# |& was added to Bash 4 as an abbreviation for 2>&1 |.
i>&j
# Redirects file descriptor i to j.
# All output of file pointed to by i gets sent to file pointed to by j.
>&j
# Redirects, by default, file descriptor 1 (stdout) to j.
# All stdout gets sent to file pointed to by j. |
0< FILENAME
< FILENAME
# Accept input from a file.
# Companion command to ">", and often used in combination with it.
#
# grep search-word <filename
[j]<>filename
# Open file "filename" for reading and writing,
#+ and assign file descriptor "j" to it.
# If "filename" does not exist, create it.
# If file descriptor "j" is not specified, default to fd 0, stdin.
#
# An application of this is writing at a specified place in a file.
echo 1234567890 > File # Write string to "File".
exec 3<> File # Open "File" and assign fd 3 to it.
read -n 4 <&3 # Read only 4 characters.
echo -n . >&3 # Write a decimal point there.
exec 3>&- # Close fd 3.
cat File # ==> 1234.67890
# Random access, by golly.
|
# Pipe.
# General purpose process and command chaining tool.
# Similar to ">", but more general in effect.
# Useful for chaining commands, scripts, files, and programs together.
cat *.txt | sort | uniq > result-file
# Sorts the output of all the .txt files and deletes duplicate lines,
# finally saves results to "result-file". |
输入和输出重定向和/或管道的多个实例可以组合在单个命令行中。
command < input-file > output-file # Or the equivalent: < input-file command > output-file # Although this is non-standard. command1 | command2 | command3 > output-file |
多个输出流可以重定向到一个文件。
ls -yz >> command.log 2>&1 # Capture result of illegal options "yz" in file "command.log." # Because stderr is redirected to the file, #+ any error messages will also be there. # Note, however, that the following does *not* give the same result. ls -yz 2>&1 >> command.log # Outputs an error message, but does not write to file. # More precisely, the command output (in this case, null) #+ writes to the file, but the error message goes only to stdout. # If redirecting both stdout and stderr, #+ the order of the commands makes a difference. |
子进程继承打开的文件描述符。这就是管道工作的原因。要防止 fd 被继承,请关闭它。
# Redirecting only stderr to a pipe. exec 3>&1 # Save current "value" of stdout. ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls'). # ^^^^ ^^^^ exec 3>&- # Now close it for the remainder of the script. # Thanks, S.C. |
有关 I/O 重定向的更详细介绍,请参见附录 F。
| [1] | 按照 UNIX 和 Linux 中的约定,数据流和外围设备(设备文件)被视为文件,其方式类似于普通文件。 |
| [2] | 文件描述符 只是操作系统分配给打开文件以跟踪它的一个数字。可以将其视为简化类型的文件指针。它类似于 C 中的 文件句柄。 |
| [3] | 使用文件描述符 5可能会导致问题。当 Bash 创建子进程时,例如使用 exec,子进程会继承 fd 5(参见 Chet Ramey 的存档电子邮件,主题:回复:文件描述符 5 保持打开状态)。最好不要管这个特定的 fd。 |