Shell输入输出重定向

一、文件描述符

英文是file descriptor简称fd。
文件描述符是一个非负整数。它是一个索引值,指向进程打开的文件。
Linux程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。
每个文件描述符会与一个打开的文件相对应。
不同的文件描述符也可能指向同一个文件。

在Linux中,每一个进程打开时都会自动获取3个文件描述符0、1和2,分别表示标准输入、标准输出、和标准错误,如果要打开其他文件,则文件描述符必须从3开始标识。

文件描述符文件名类型指向硬件
0/dev/stdin标准输入文件键盘
1/dev/stdout标准输出文件显示器
2/dev/stderr标准错误输出文件显示器
$ ll /dev/std*
lrwxrwxrwx 1 root root 15 Apr 2 07:57 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Apr 2 07:57 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Apr 2 07:57 /dev/stdout -> /proc/self/fd/1

$ ll /proc/self/fd/
total 0
lrwx------ 1 root root 64 Apr 6 03:53 0 -> /dev/pts/2
lrwx------ 1 root root 64 Apr 6 03:53 1 -> /dev/pts/2
lrwx------ 1 root root 64 Apr 6 03:53 2 -> /dev/pts/2
lr-x------ 1 root root 64 Apr 6 03:53 3 -> /proc/14038/fd

二、重定向

重定向分为两种,一种输入重定向,一种是输出重定向;
从字面上理解,输入输出重定向就是「改变输入与输出的方向」的意思。可以把重定向理解为指向。

(一)输出重定向


输出重定向是指命令的结果不再输出到显示器上,而是输出到其它地方,一般是文件中。
这样做的最大好处就是把命令的结果保存起来,当我们需要的时候可以随时查询。

1.标准输出重定向

command 1>file 以覆盖的方式,把command的正确输出结果输出到file文件中。

command 1>>file 以追加的方式,把command的正确输出结果输出到file文件中。

2.标准错误重定向

command 2>file 以覆盖的方式,把command的错误信息输出到file文件中。

command 2>>file 以追加的方式,把command的错误信息输出到file文件中。

3.标准输出与标准错误同时重定向

command 1>file1 2>file2  以覆盖的方式,把正确的输出结果输出到file1文件中,把错误信息输出到file2文件中。

command 1>>file1  2>>file2 以追加的方式,把正确的输出结果输出到file1文件中,把错误信息输出到file2文件中。

command 1>file 2>file 以覆盖的方式,把正确输出和错误信息同时保存到同一个文件file中。不推荐这种方式。

command 1>>file 2>>file 以追加的方式,把正确输出和错误信息同时保存到同一个文件file中。

注意
(1)输出重定向的完整写法是fd>file或者fd>>file,其中fd表示文件描述符,如果不写,默认为1,也就是标准输出文件。
当文件描述符为大于1的值时,比如2,就必须写上。
(2)fd和>之间不能有空格,否则Shell会解析失败;>和file之间的空格可有可无。为了保持一致,我习惯在>两边都不加空格。

4./dev/null文件
如果你既不想把命令的输出结果保存到文件,也不想把命令的输出结果显示到屏幕上,干扰命令的执行,那么可以把命令的所有结果重定向到/dev/null文件中。
大家可以把 /dev/null 当成Linux 系统的垃圾箱,任何放入垃圾箱的数据都会被丢弃,不能恢复。

command 1>/dev/null 2>/dev/null

5.用法举例

(1)标准输出重定向

echo 'hello world' >foobar.txt
cat foobar.txt

运行结果:
hello world

echo 'hello world' >>foobar.txt
cat foobar.txt

运行结果:
hello world
hello world

(2)标准错误重定向

ls foobar 2>err.log
cat err.log

运行结果:
ls: 无法访问 'foobar': 没有那个文件或目录

(3)标准输出与标准错误同时重定向

ls >out.log 2>err.log
ls foobar >>out.log 2>>err.log
cat out.log
cat err.log

(4)输出到/dev/null文件

ls foobar >/dev/null 2>/dev/null

(二)输入重定向


输入重定向就是改变输入的方向,不再使用键盘作为命令输入的来源,而是使用文件作为命令的输入。
命令必须能接受标准输入作为参数。

1.标准输入重定向

command 0<file  将file文件中的内容作为command的输入。

2.here document
格式如下:

command 0<<delimiter
document
delimiter

Here Document是Shell中的一种特殊的重定向方式,将两个delimiter之间的内容document作为输入。

注意
delimiter可以是任意字符串。
开始的delimiter后面必须是一个换行符。
结尾的delimiter一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。

3.here string
格式如下:

command 0<<<string 将字符串string作为输入
cat <<<'hello world'

等同于

echo 'hello world' | cat

注意
输入重定向的完整写法是fd<file,其中fd表示文件描述符,如果不写,默认为0,也就是标准输入文件。

4.用法举例
(1)输入重定向
统计文档中有多少行文字。

wc -l foobar.txt
2 foobar.txt

wc -l <foobar.txt
2

上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。

(2)逐行读取文件内容。

while read str; do
     echo $str
done <foobar.txt

这种写法叫做代码块重定向,也就是把一组命令同时重定向到一个文件。

(3)Here Document

wc -l <<eof
foo
bar
eof

也可以将Here Document用在脚本中,例如:

#!/bin/bash
cat <<eof
foo
bar
eof

(4)here string
批量重命名文件名含有空格的文件
重命名前:

txt 2014.02.14.log
txt 2014.02.15.log

重命名后:

txt_2014_02_14.log
txt_2014_02_15.log

脚本内容

oldifs=$IFS
IFS=$'\n'
for file in `ls`;do
     mv $file `sed -r 's/[ .]/_/g;s/(.*)_/\1./' <<< $file`
done
IFS=$oldifs

(三)输入和输出同时重定向

command 0<file1 1>file2 将file1作为command的输入,并将command的正确结果输出到file2。 

(四)文件描述符复制


文件描述符的复制是指将一个文件描述符指向另一个文件描述符指向的文件。使用”&”进行复制。

n<&m:n指向m指向的文件。作为输入

n>&m:n指向m指向的文件。作为输出

可以发现总是前面指向后面,即n指向m。
例如,3>&1表示3指向1指向的文件,1指向的文件是/dev/stdout,3也重定向到/dev/stdout,以后进程将数据写入3的时候,将直接输出到屏幕。这里的3>&1等价于3>/dev/stdout。如果后面改变了1指向的文件,由于3的目标仍然是/dev/stdout,所以可以拿3来还原1使其目标变回/dev/stdout。

为什么不用n<m与n>m呢?
因为<与>后面必须是文件名,不支持文件描述符。如果使用2>1,它会把1解释成文件名。所以就有了&,专门用来处理两个文件描述符的重定向。

command 1>file 2>&1 以覆盖的方式,把正确输出和错误信息同时保存到同一个文件file中。

command 1>>file 2>&1 以追加的方式,把正确输出和错误信息同时保存到同一个文件file中。

command &>file 以覆盖的方式,把正确输出和错误信息同时保存到同一个文件file中。

command &>>file 以追加的方式,把正确输出和错误信息同时保存到同一个文件file中。

&>是一种特殊写法,&>file等价于1>file 2>&1

(五)重定向的执行顺序


重定向顺序很重要:1>file 2>&1和2>&1 1>file是不同的。

1>file 2>&1。这里分两个过程:先将1重定向到file文件;之后再将2指向1,1此时已经重定向到file文件上,因此2也重定向到file。所以,最终的结果是标准输出重定向到file,标准错误也重定向到file。

2>&1 1>file。这里也分两个过程:先将2指向1,而此时1重定向的文件是默认的/dev/stdout,所以2也重定向到/dev/stdout;之后再将1重定向到file文件。也就是说,这里的标准错误和标准输出仍然是分开输出的。所以,最终的结果是标准错误输出到/dev/stdout,即屏幕上,而标准输出将输出到file文件中。

例子:

ls foobar >foobar.txt 2>&1
ls foobar 2>&1 >foobar.txt

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值