本文将聚焦 Linux Shell 中重定向操作的核心概念、使用方法和实战场景,展示其如何通过改变标准输入、输出和错误的默认流向,在命令与文件之间建立灵活的数据通道,从而实现对命令行输入输出的精准控制,提升任务自动化、日志记录和数据处理的效率与可靠性。
[本文基于 CentOS Linux release 7 系统环境]
前情提要:通过往期文章《【Linux·基础篇】Shell 基础|管道:命令的连接器》的内容,我们了解了管道的核心概念和使用方法。
掌握了管道,我们就能让数据在命令之间流畅穿梭、实时处理。
在 Linux 的 Shell 世界里,每一个命令都像一个小型工厂:它从“标准输入”接收原材料,在“标准输出”吐出成品,遇到问题则在“标准错误”发出警报。默认情况下,输入来自我们的键盘,输出显示在屏幕(终端)。但如果我们想改变这种默认的数据流向呢?比如,你是否想过这两个问题:
简言之,想让命令从文件读取数据,或将结果保存到文件,该如何呢?此时,就需要请出管道的“黄金搭档”——重定向。
掌握了重定向,我们就可以轻松地掌控数据流向。
如果说管道是连接命令与命令的“连接器”,可以将多个独立的命令串联起来,构成一条数据流,那么重定向就是这条数据流的“指挥棒”。
重定向不负责连接命令,也不处理数据,而是决定了这条数据流(或任何单一命令)的起点和终点,即重新定义数据的来源与去向(输入与输出),比如指挥数据是“从屏幕来还是从文件来”,以及“到屏幕去还是到文件去”。
接下来,我们就来解锁这项让命令的输入输出完全听我们指挥的核心技能,让我们的命令操作更加高效、灵活。
当我们希望将命令的“正常输出结果(即标准输出)”保存到文件,而不是显示在屏幕上时,就需要使用标准输出重定向。
标准输出重定向通过 > 和 >> 这两种符号,为标准输出提供了两种写入文件的模式:覆盖模式与追加模式。
> 符号command > file# 将 ls 命令的结果保存到 list.txt 文件中,屏幕不再显示ls -l > list.txt# 覆盖已存在的文件echo "这是新内容" > existing_file.txt>> 符号command >> file> 类似,但会将命令的标准输出追加到指定文件的末尾(保留原内容并在文件末尾接着写),而不是覆盖,非常适合用于记录日志。# 将当前日期时间追加到 log.txt 文件的末尾date >> log.txt# 多次追加构建日志echo "=== 脚本开始 ===" > script.logsome_command >> script.logecho "=== 脚本结束 ===" >> script.log程序运行时的错误信息默认通过“标准错误”通道输出,我们也可以单独管理它,避免错误信息干扰正常输出。
类似地,标准错误重定向通过 2> 和 2>> 这两种符号,为标准错误提供了两种写入文件的模式:覆盖模式与追加模式。
2> 符号command 2> file2 是标准错误流的文件描述符编号。# 尝试查看一个不存在的文件,错误信息会被保存到 error.log,屏幕不显示ls not_exist_file 2> error.log# 查看文件,正常结果到屏幕,错误到文件find / -name "*.conf" 2> errors.txt2>> 符号command 2>> file# 将多个命令的错误信息累积记录command1 2>> all_errors.logcommand2 2>> all_errors.log我们可以将前面几种有关输出的重定向组合使用,实现对输出更精细的控制。
command > output_file 2> error_file# 正常结果进 output.txt,错误信息进 errors.txtsome_script.sh > output.txt 2> errors.txt# 编译程序,结果和错误分开记录gcc program.c > compile_output.txt 2> compile_errors.txt# 传统写法command > file 2>&1 # 覆盖模式command >> file 2>&1 # 追加模式# 现代简写command &> file # 覆盖模式command &>> file # 追加模式2>&1 表示“将标准错误合并到标准输出流”,更简洁的现代写法是 &>。# 将所有输出(无论正常还是错误)都保存到 all_output.log# 传统写法./some_script.sh > all_output.log 2>&1 # 覆盖模式./some_script.sh >> all_output.log 2>&1 # 追加模式# 现代写法./some_script.sh &> all_output.log # 覆盖模式./some_script.sh &>> all_output.log # 追加模式/dev/null在 Linux 中,/dev/null 是一个特殊的设备文件,被称为“黑洞设备”或“空设备”。所有写入它的数据都会被永久丢弃,读取它则立即返回文件结束。
在这里我们主要介绍对 /dev/null 的写入。以下介绍静默执行命令的几种方式。
command > /dev/null # 仅丢弃标准输出command 2> /dev/null # 仅丢弃标准错误command &> /dev/null # 丢弃所有输出(现代简写)command > /dev/null 2>&1 # 丢弃所有输出(传统写法)/dev/null 设备,相当于完全丢弃输出。这在我们希望完全静默运行命令,丢弃所有输出时非常有用,例如运行脚本时不需要看到任何输出,或者只想检查命令是否成功执行(通过返回值)。# 忽略特定命令的警告信息find / -name "*.log" 2> /dev/nullmake 2> /dev/null# 后台运行服务,不产生任何输出nohup my_service &> /dev/null &nohup some_daemon > /dev/null 2>&1 &# 只检查命令是否成功,不关心输出内容if grep "pattern" file.txt > /dev/null 2>&1; then echo "模式找到"fiif ping -c1 example.com &> /dev/null; then echo "主机可达"fi除了管理输出,我们还可以改变命令输入的来源,让“标准输入”从外部文件读取。
< 符号command < file# 从文件读取邮件内容发送# 假设 mail_content.txt 文件里是一封邮件正文,用 mail 命令发送mail -s "通知" user@example.com < mail_content.txt# 统计文件的行数、单词数、字符数wc < document.txt# 对文件内容排序sort < unsorted_list.txt > sorted_list.txt# 批量创建用户while read username; do useradd "$username"done < user_list.txt# 从配置文件读取设置source <(grep '^export' config.env)Here Document 是输入重定向的一种特殊形式(内联形式),它允许我们直接在命令行中为命令指定多行输入数据,而无需依赖外部文件。
<< 符号command << DELIMITER输入数据...多行数据...DELIMITER<< 后面的 DELIMITER 是一个自定义的终止标记词(定界符),例如可以自定义为 EOF、END。Shell 会将接下来直到再次遇到这个标记词的所有行,都作为命令的标准输入。常用于脚本中向交互式命令批量传递参数。# 向 cat 命令传递多行文本,cat 会将其原样输出cat << EOF这是第一行。这是第二行。这里是终止标记 EOF 之前的所有内容都会被输出。EOF# 生成脚本或配置文件cat > setup.sh << 'EOF'#!/bin/bashecho "开始安装..."# 安装步骤EOFchmod +x setup.sh# 在脚本中为命令提供多行输入进行批量配置ftp -n << END_SCRIPTopen ftp.example.comuser username passwordget file.txtquitEND_SCRIPT# 向交互式程序提供输入sudo passwd user1 << EOFnewpasswordnewpasswordEOF重定向是 Shell 编程的基石之一,它打破了命令只能与人交互的限制,架起了命令与命令、命令与文件之间数据流通的桥梁。从简单的保存列表,到复杂的日志记录和脚本输入,都离不开它。
通过 /dev/null 这个特殊的“黑洞设备”,我们还能实现完全静默的命令执行,这在自动化脚本和后台任务中尤其有用。而 <、<< 等输入重定向则让我们能够轻松地从文件或其他来源获取输入,大大扩展了命令的灵活性。
建议你不妨现在就去打开终端,用 ls、echo 等简单命令配合 >、>>、2>、/dev/null 多做几次练习。当你习惯了让数据“指哪儿打哪儿”,你会发现 Linux 命令行的高效与优雅,又向你敞开了一扇新的大门。
最后,我们可以将重定向与管道进行简单的对比。
| 核心功能 | ||
| 数据流向 | ||
| 主要符号 | ><, >>, 2> | | |
| 典型用途 | ||
| 举例 | ls > list.txtls 的结果,存入文件 list.txt。 | ls | grep ".txt"ls 的结果,传给grep 过滤。 |
二者各司其职,也常强强联合。比如,我们可以先用管道组合多个命令进行复杂处理,最后用重定向将成果保存:
command1 | command2 > fileps aux | grep python | wc -l > python_count.txt此番炼器手札,炉火尚未全熄。若道友观之有趣,或可暂留此间,结一尘缘。待下回开炉铸器,新得感悟,必先与同道分享。