使用重定向呈现数据
输入和输出信息
Linux特殊的文件描述符:
| 文件描述符 | 缩写 | 描述 |
|---|---|---|
| 0 | STDIN | 标准输入文件 |
| 1 | STDOUT | 标准输出文件 |
| 2 | STDERR | 标准错误文件 |
- 这三个特殊文件描述符会处理脚本的输入和输出。shell用它们将shell默认的输入和输出导向到相应的位置。
STDIN(标准输入)
对终端界面来说,标准输入文件对应的资源是键盘。
当在命令行上只输入
cat命令时,它会从文件描述符0接收输入。输入一行内容,cat命令就会显示出一行完全相同的内容。ubuntu@sh:~$ cat Hello World Hello WorldSTDOUT(标准输出)
程序会将正确信息导向文件描述符
1,默认情况下文件描述符1和标准输出文件关联,信息最终会被输出到显示器中。ubuntu@sh:~$ date > test3 ubuntu@sh:~$ cat test3 2023年 03月 26日 星期日 19:23:54 PDTSTDERR(标准错误)
程序会将错误信息导向文件描述符
2,默认情况下文件描述符2和标准错误文件关联,信息最终同样会被输出到显示器中。ubuntu@sh:~$ ls badfile >test4 ls: 无法访问 'badfile': 没有那个文件或目录 (No such file or directory) ubuntu@sh:~$ cat test4 # 标准错误重定向使用的是'2>' ubuntu@sh:~$ ls badfile 2>test4 ubuntu@sh:~$ cat test4 ls: 无法访问 'badfile': 没有那个文件或目录 (No such file or directory) ubuntu@sh:~$
输入重定向
输入重定向和输出重定向正好相反。输入重定向将文件的内容重定向到命令,而非将命令的输出重定向到文件。输入重定向符号是小于号(<)
ubuntu@sh:~$ cat test6
Sun Mar 26 19:23:54 PDT 2023
ubuntu tty1 2023-03-26 19:01
ubuntu pts/0 2023-03-26 19:01 (192.168.13.1)
ubuntu@sh:~$ wc < test6
3 15 122
ubuntu@sh:~$
wc命令可以对对数据中的文本进行计数。默认情况下,它会输出3个值:文本的行数,文本的词数,文本的字节数。
输出重定向
ubuntu@sh:~$ date > test6
ubuntu@sh:~$ ls -l test6
-rw-rw-r-- 1 ubuntu ubuntu 29 Mar 26 19:23 test6
ubuntu@sh:~$ cat test6
Sun Mar 26 19:23:54 PDT 2023
ubuntu@sh:~$
作业1:理解并执行上述输入重定向、输出重定向的使用案例。
重定向操作符创建了一个文件 test6(通过默认的 umask设置),并将 date命令的输出重定向到该文件中。如果输出文件已经存在了,重定向操作符会用新的文件数据覆盖已有文件。
有时,可能并不想覆盖文件原有内容,而是想要将命令的输出追加到已有文件中,比如正在创建一个记录系统上某个操作的日志文件。在这种情况下,可以用双大于号 (>>)来追加数据。
ubuntu@sh:~$ who >> test6
ubuntu@sh:~$ cat test6
Sun Mar 26 19:23:54 PDT 2023
ubuntu tty1 2023-03-26 19:01
ubuntu pts/0 2023-03-26 19:01 (192.168.13.1)
ubuntu@sh:~$
test6文件在原来who命令输出的基础上又加上了date命令的输出
错误重定向
只重定向错误信息
STDERR文件描述符被设成2。可以选择只重定向错误消息,将该文件描述符值放在重定向符号前。
ubuntu@sh:~$ ls -al badfile 2> test3 ubuntu@sh:~$ cat test3 ls: 无法访问 'badfile': 没有那个文件或目录 (No such file or directory) ubuntu@sh:~$重定向错误和正常输出
如果想重定向错误和正常输出,必须用两个重定向符号。需要在符号前面放上待重定向数据所对应的文件描述符,然后指向用于保存数据的输出文件。
ubuntu@sh:~$ ls -al test3 test6 badtest 2>test7 1>test8 ubuntu@sh:~$ cat test7 ls: 无法访问 'badtest': 没有那个文件或目录 (No such file or directory) ubuntu@sh:~$ cat test8 -rw-rw-r-- 1 ubuntu ubuntu 55 Mar 26 20:24 test3 -rw-rw-r-- 1 ubuntu ubuntu 122 Mar 26 19:27 test6 ubuntu@sh:~$shell利用
1>符号将ls命令的正常输出重定向到了test8文件,而这些输出本该是进入STDOUT的。所有本该输出到STDERR的错误消息通过2>符号被重定向到了test7文件。可以用这种方法将脚本的正常输出和脚本生成的错误消息分离开来。这样就可以轻松地识别出错误信息。另外也可以将
STDERR和STDOUT的输出重定向到同一个输出文件。为此bash shell提供了特殊的重定向符号&>。ubuntu@sh:~$ ls -al badtest test3 test6 badtest &> test7 ubuntu@sh:~$ cat test7 ls: 无法访问 'badtest': 没有那个文件或目录 (No such file or directory) ls: 无法访问 'badtest': 没有那个文件或目录 (No such file or directory) -rw-rw-r-- 1 ubuntu ubuntu 55 Mar 26 20:24 test3 -rw-rw-r-- 1 ubuntu ubuntu 122 Mar 26 19:27 test6
在脚本中重定向输出
有两种方法来在脚本中重定向输出:
- 临时重定向行输出
- 永久重定向脚本中的所有命令
临时重定向
如果有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR。所需要做的是使用输出重定向符>来将输出信息重定向到STDERR文件。在重定向到文件描述符时,必须在文件描述符数字之前加一个&:
ubuntu@sh:~$ cat test.sh
#!/bin/bash
echo "这是一个错误信息" >&2
echo "这是正常输出"
ubuntu@sh:~$ bash test.sh 2> test9
这是正常输出
ubuntu@sh:~$ cat test9
这是一个错误信息
作业2:理解并执行脚本中实现临时输出重定向的方法。
永久重定向
如果脚本中有大量数据需要重定向,那么重定向每一行 echo 语句就会很繁琐。可以使用 exec 命令告诉 shell 在脚本执行期间重定向某个特定文件描述符。
#!/bin/bash
# 演示永久重定向:将脚本内所有标准输出重定向到标准错误
exec 1>&2
echo "[运行中] 这是一个将所有输出重定向到外部文件的测试"
echo "[运行中] 正在处理数据..."
echo "[完成] 所有输出已成功发送到重定向目标,无需逐行手动重定向"
ubuntu@sh:~$ bash test.sh
[运行中] 这是一个将所有输出重定向到外部文件的测试
[运行中] 正在处理数据...
[完成] 所有输出已成功发送到重定向目标,无需逐行手动重定向
脚本执行过程中切换重定向目标:
#!/bin/bash # 演示在脚本执行过程中动态重定向输出到不同位置 # 1. 首先将错误信息重定向到 testerror 文件 exec 2>testerror echo "[开始] 脚本启动,准备执行测试" # 2. 将后续的所有标准输出重定向到 testout 文件 echo "[配置] 现在开始将所有标准输出导向至 testout 文件" exec 1>testout echo "[输出] 这行文字会被保存到 testout 文件中" echo "[输出] 正在生成报告数据..." echo "[输出] 但这行信息会被导向到标准错误(testerror 文件)" >&2
作业1:理解并执行上述脚本内实现永久输出重定向的方法。
在脚本中重定向输入
可以使用与脚本中重定向STDOUT和STDERR相同的方法来将STDIN从键盘重定向到其他位置。exec命令允许将STDIN重定向到Linux系统上的文件中。这个重定向只要在脚本需要输入时就会作用
#!/bin/bash
# 演示在脚本中重定向文件输入
# 将标准输入 STDIN 重定向到外部文件 testfile
exec 0< testfile
count=1
# 现在 read 命令将从 testfile 逐行读取内容
while read line
do
echo "[读取中] 第 $count 行内容为: $line"
count=$((count + 1))
done
创建自定义的文件描述符
创建并打开输出文件描述符
在脚本中重定向输入和输出时,并不局限于这 3 个默认的文件描述符。在 shell 中最多可以有 9 个打开的文件描述符(3~8 均可用)。
#!/bin/bash
# 演示分配自定义文件描述符 3 为输出流
exec 3>test3out
echo "[提示] 这条消息将直接显示在屏幕终端上"
echo "[文件写入] 而这条消息将被存储到自定义文件 test3out 中" >&3
echo "[提示] 完成写入,现在回到屏幕输出"
创建并打开输入文件描述符
同样可以重定向自定义的输入文件描述符。一种常见的技巧是:在重定向到文件之前,先将默认的 STDIN (0) 备份到另一个空闲的文件描述符中,处理完文件后再将其恢复回来。
#!/bin/bash
# 演示使用自定义文件描述符 6 备份并恢复标准输入
# 1. 将自定义描述符 6 设为标准输入(备份)
exec 6<&0
# 2. 将标准输入重定向到 testfile 执行批量读取
exec 0< testfile
count=1
while read line
do
echo "[读取中] 第 $count 行: $line"
count=$((count + 1))
done
# 3. 恢复标准输入为键盘,通过 6 号描述符导回
exec 0<&6
read -p "[交互] 您已完成文件读取,是否结束程序? (y/n) " answer
case $answer in
Y|y) echo "Goodbye";;
N|n) echo "Sorry, this is the end.";;
esac
作业2:脚本内创建输入文件描述符并实现输入重定向的代码。
组织命令输出
有时候,可能不想显示脚本的输出。这在将脚本作为后台进程运行时很常见。可以将STDERR重定向到一个叫作null文件的特殊/文件。shell输出到null文件的任何数据都不会保存,全部都被丢掉了。在Linux系统上null文件的标准位置是/dev/null。你重定向到该位置的任何数据都会被丢掉,不会显示。
ubuntu@sh:~$ ls -al > /dev/null
ubuntu@sh:~$
ubuntu@sh:~$ ls -al badfile 2> /dev/null
ubuntu@sh:~$