在编写 shell 脚本时,容易对重定向与管道的概念产生混淆。本文总结了一些关于在 shell 中运用重定向和管道的经验。
重定向
重定向,即输入输出重定向。文章主要研究对象为 linux 标准输入、标准输出和标准错误输出,linux 定义了0、1、2
三个文件描述符,分别对应标准输入、标准输出和标准错误输出。 输出重定向符1>
标准输出重定向符,可简写为>
2>
标准错误重定向符&>
标准输出与标准错误输出重定向符(在某些场合使用会出问题,如crontab
。尽量用cmd > file 2>&1
代替)1>&2
标准输出重定向至标准错误输出(作为整体理解)2>&1
标准错误输出重定向至标准输出(作为整体理解)1>>
标准输出重定向,追加2>>
标准错误输出重定向,追加
重定向至文件<linux shell command> 输出重定向符 <linux file>
,如:
文件描述符重定向ls > abc ls 2> def
ls > abc 2>&1 tmp=`git status 2>&1`
输入重定向
<
标准输入重定向<linux shell command> 输入重定向符 <linux file>
,把 linux 文件内容作为 shell 命令的输入,如:wc < /etc/fstab
<<
分隔符控制输入重定向
分隔符之间的内容作为 shell 命令的输入<linux shell command> 分隔符控制输入重定向 分隔符 输入内容1 输入内容2 输入内容3 ... 分隔符
vi myfile <<abcdef i This is line 1 This is line 2 ^[ zz abcdef
小结
除文件描述符重定向、分隔符控制输入重定向外,其他重定向符的一端是 shell 命令,另一端是 linux 文件。要么是 linux 文件内容作为 shell 命令的输入,要么是 linux 文件存放 shell 命令的输出结果。
如果不使用重定向符,则 shell 命令的默认输入为标准输入:键盘; shell 命令的默认输出为标准输出:显示器。从 linux 操作系统角度,标准输入输出都是 linux 文件,把默认输入输出看成隐形的重定向,则隐形重定向符的一端仍是 shell 命令,另一端仍是 linux 文件。
管道
|
管道符<linux shell command> 管道符 <linux shell command>
,管道符连接两个 shell 命令,把前一个 shell 命令的标准输出作为后一个 shell 命令的标准输入,如:ls | wc cat /etc/fstab | wc
小结:使用管道时,管道符两端都是 shell 命令
区分重定向和管道
简而言之,重定向在 shell 命令和 linux 文件之间起作用,管道在两个 shell 命令之间起作用
此外,管道的实现机制是 linux 的 IPC 机制,即进程间通信,使用管道时,系统会使用新的进程运行管道中的 shell 命令。因此,当前 shell 中的变量与管道中 shell 命令使用的变量存在于不同的进程环境中,管道中 shell 命令改变的变量不会影响当前 shell 中的变量补充:用户自定义变量与标准输出
shell 命令的 标准输出 可给用户自定义变量赋值,但 标准错误输出 不能直接给用户自定义变量赋值
a=`ls`
echo "$a"
几个例子:
获取 git 的执行结果(1)
a=`git status -s`
echo $?
echo $a
如果第一行命令执行出错,标准错误输出 将在屏幕上显示错误信息,但 a
的值为空,因为 a
没有从 标准输出 获取到任何内容
获取 git 的执行结果(2)
a=`git status -s 2>&1`
echo $?
echo $a
第一行命令把 标准错误输出 重定向至 标准输出,此时 a
能够获取 git 执行结果的报错信息
获取 git 的执行结果(3)
a=`git status -s 2>/dev/null`
echo $?
echo $a
第一行命令把 标准错误输出 重定向至 /dev/null
,屏幕上将不会出现任何报错信息,a
仍从 标准输出 获取 git 的执行结果