Linux重定向

1. 定义:

Linux重定向是指修改默认选项,对执行方式进行修改,将输入输出重定向到所期望的场景。

2. 文件描述符(file description,fd)

文件描述符是IO重定向中的重要概念。文件描述符使用数字表示,它指明了数据的流向特征。

软件设计认为,程序应该有一个数据来源、数据出口和报告错误的地方。在Linux系统中,它们分别使用描述符0、1、2来表示,这3个描述符默认的目标文件(设备)分别是/dev/stdin、/dev/stdout、/dev/stderr,它们分别是各个终端字符设备的软链接,分别代表的是标准输入,标准输出与标准错误。

┌──(root💀kali)-[~]
└─# ll /dev/std*                                                                                        16 ⨯
lrwxrwxrwx 1 root root 15 Mar  4 12:58 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Mar  4 12:58 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Mar  4 12:58 /dev/stdout -> /proc/self/fd/1

┌──(root💀kali)-[~]
└─# ll /proc/self/fd/
total 0
lrwx------ 1 root root 64 Mar  4 13:01 0 -> /dev/pts/0
lrwx------ 1 root root 64 Mar  4 13:01 1 -> /dev/pts/0
lrwx------ 1 root root 64 Mar  4 13:01 2 -> /dev/pts/0
lr-x------ 1 root root 64 Mar  4 13:01 3 -> /proc/2602/fd
                                                                                                             

在Linux中,每一个进程打开时都会自动获取3个文件描述符0、1和2,分别表示标准输入、标准输出、和标准错误,如果要打开其他文件,则文件描述符必须从3开始标识。对于我们人为要打开的描述符,建议使用9以内的描述符,超过9的描述符可能已经被系统内部分配给其他进程。

类型 文件描述符 默认情况 对应文件句柄位置
标准输入(standard input) 0 从键盘获得输入 /proc/self/fd/0
标准输出(standard output) 1 输出到屏幕(即控制台) /proc/self/fd/1
错误输出(error output) 2 输出到屏幕(即控制台) /proc/self/fd/2

文件描述符就是系统为了跟踪这个打开的文件而分配给它的一个数字,这个数字和文件绑定在一起,数据流入描述符的时候也表示流入文件。而Linux中万物皆文件,这些文件都可以分配描述符,包括套接字。


输出重定向

命令 介绍
command >file 把标准输出(stdout)重定向到 file 文件中;
command 1>file 同上;
command >>file 把 stdout 重定向到 file 文件中(追加);
command 1>>file 同上;
command 2>file 把标准错误(stderr)重定向到 file 文件中;
command 2>>file 把 stderr重定向到 file 文件中(追加);
command >> file 2>&1 把 stdout 和 stderr 一起重定向到 file 文件中(追加);

我们使用>或者>>对输出进行重定向。符号的左边表示文件描述符,如果没有的话表示1,也就是标准输出,符号的右边可以是一个文件,也可以是一个输出设备(Linux中万物皆文件,即设备也是文件)。当使用>时,会判断右边的文件存不存在,如果存在的话就先删除,然后创建一个新的文件,不存在的话则直接创建。但是当使用>>进行追加时,则不会删除原来已经存在的文件。

格式

command-line [n]> 文件

这条命令意思是:将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的) 重定向其它输出设备(文件)1,2分别是标准输出,错误输出。

实例

#查看文件内容,1.txt  2.txt (其中2.txt文件不存在)
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt
this is a.txt
cat: 2.txt: No such file or directory
 
#标准输出与错误输出都显示在屏幕了,
#现在需要把标准输出写入到1.log中
# 1>可以省略,表示标准输出
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt 1>1.log
cat: 2.txt: No such file or directory
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt >1.log
cat: 2.txt: No such file or directory
[root@sccprocddev02:/home/upro01]cat 1.log
this is a.txt
 
#标准输出不输出到屏幕,输出到1.log中
#错误输出不输出到屏幕,输出到2.log中
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt 1>1.log 2>2.log
[root@sccprocddev02:/home/upro01]cat 1.log 2.log
this is a.txt
cat: 2.txt: No such file or directory
 
#将标准输出和错误输出分别追加到文件1.log和2.log中  “>>”追加操作符
#可以看到两个文件分别多出一行输出的内容
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt 1>>1.log 2>>2.log
[root@sccprocddev02:/home/upro01]cat 1.log 2.log
this is a.txt
this is a.txt
cat: 2.txt: No such file or directory
cat: 2.txt: No such file or directory

 
#高级用法(具体讲解后面会提到)
#将错误输出信息关闭掉,控制台只打印了标准输出
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt 2>&-
this is a.txt
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt 2>/dev/null
this is a.txt
#&[n] 代表是已经存在的文件描述符,&1 代表输出 &2代表错误输出&-代表关闭与它绑定的描述符
#/dev/null 这个设备,是linux 中黑洞设备,什么信息只要输出给这个设备,都会给吃掉
  
#关闭所有输出
#关闭 1 ,2 文件描述符
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt 1>&- 2>&-
 
#将1,2 输出转发给/dev/null设备
[chengmo@centos5 shell]$ ls test.sh test1.sh  2>/dev/null 1>/dev/null
 
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt >/dev/null 2>&1
#将标准输出fd=1重定向到/dev/null文件,然后将fd=2重定向到fd=1所绑定的/dev/null文件。这种常用文件描述符前必须有个 &, 否则2>1就变成将错误输出输出到一个名为1的文件。
[root@sccprocddev02:/home/upro01]cat 1.txt 2.txt &>/dev/null
#&>代表将标准输出与标准错误重定向到/dev/null文件

输入重定向
在理解了输出重定向之后,理解输入重定向就会容易得多。对输入重定向的基本命令如下:

命令 介绍
command <filename 以filename文件作为标准输入;
command 0<filename 同上;
command < file >file2 command命令以 file 文件作为标准输入(stdin),以 file2文件作为stdout;
cat <>file 以读的方式打开 file;

我们使用<对输入做重定向,如果符号左边没有写值,那么默认就是0。
格式:

command-line [n] <文件

命令默认从键盘获得的输入,使用输入重定向改成从文件,或者其它打开文件以及设备输入。执行这个命令,将标准输入0,与文件或设备绑定,将由它进行输入。

实例:

[root@sccprocddev02:/home/upro01]cat > stdout.txt
this is stdout.txt
^C
[root@sccprocddev02:/home/upro01]cat stdout.txt
this is stdout.txt
#这里使用ctrl+d 或者ctrl+c退出输入
#从标准输入[键盘]获得数据,然后输出给stdout.txt文件
  
[root@sccprocddev02:/home/upro01]cat > stdout2.txt < stdout.txt
[root@sccprocddev02:/home/upro01]cat stdout2.txt
this is stdout.txt
#从stdout.txt获得输入数据,然后输出给文件stdout2.txt
  
  
[root@sccprocddev02:/home/upro01]cat > stdout3.txt << end
> first line
> second line
> end
[root@sccprocddev02:/home/upro01]#cat stdout3.txt
first line
second line
#<< 这个连续两个小符号, 他代表的是[结束的输入字符]的意思。这样当空行输入end字符时,自动退出输入,不需要使用ctrl+d或者ctrl+c退出

3. 文件描述符的复制(duplicate)

文件描述符的复制表示复制文件描述符到另一个文件描述符中,也就是将该文件描述符重定向到另一个文件描述符所绑定的文件,使用”&”进行复制。

  • [n]<&[m]将文件描述符n复制于m代表的文件描述符。可以理解为文件描述符n重定向到m代表的文件描述符所绑定的文件,即m原来对应哪个文件,现在n也对应这个文件。n不指定则默认为0(标准输入就是0),表示标准输入也将输入到m所对应的文件中。

  • [n]>&[m]将文件描述符n复制于m代表的文件描述符。可以理解为文件描述符n重定向到m代表的文件描述符所绑定的文件,即m原来对应哪个文件,现在n也对应这个文件。n不指定则默认为1(标准输出就是1),表示标准输出也将输出到m所对应的文件中。

例如,3>&1表示fd=3复制于fd=1,而fd=1目前的重定向目标文件是/dev/stdout(fd=1指向与输出设备是默认的),因此fd=3也重定向到/dev/stdout,以后进程将数据写入fd=3的时候,将直接输出到屏幕。如果后面改变了fd=1的输出目标(如file1),由于fd=3的目标仍然是/dev/stdout,所以可以拿fd=3来还原fd=1使其目标变回/dev/stdout。

(fd=1) --> /dev/stdout
  |
 3>&1
  |
(fd=3) --> /dev/stdout

关于文件描述符的duplicate

在操作系统(或C)中,对于实体文件的文件描述符来说,文件描述符是用来描述它所指向的实体文件的。例如fd=5指向文件a.txt。复制(duplicate)实际上是执行dup()函数,表示创建另一个文件描述符(例如fd=6),指向同一个底层对象,例如指向同一个实体文件。这时fd=5和fd=6都将指向a.txt。
在shell中,我们将文件描述符和实体文件的关联关系(或者称为指向的关系)称为重定向,其实用更底层的指向关系更容易理解。例如,”3>&1”表示复制fd=1,使得fd=3和fd=1都指向同一个对象,也就是stdout。

再例如,cat <&1表示fd=0复制于fd=1上,而此时fd=1的重定向文件是/dev/stdout,所以fd=0也指向这个/dev/stdout文件,而cat从fd=0中读取标准输入,于是/dev/stdout既是标准输入设备,也是标准输出设备,也就是说进程从/dev/stdout(屏幕)接受输入,输入后再直接输出到/dev/stdout。以下是结果:

┌──(root💀kali)-[~]
└─# cat <&1                                                                                            130 ⨯
uegwfwuggi
uegwfwuggi

4. 重定向顺序很重要:>file 2>&12>&1 >file

想必很多人都知道>file 2>&1的作用,它等价于&>file,表示标准输出和标准错误都重定向到file中。那它和2>&1 >file有什么区别呢?

首先解释>file 2>&1。这里分两个过程:先打开file,再将fd=1重定向到file文件上,这样file文件就成了标准输出的输出目标;之后再将fd=2复制于fd=1,而fd=1此时已经重定向到file文件上,因此fd=2也重定向到file上。所以,最终的结果是标准输出重定向到file上,标准错误也重定向到file上。

再解释2>&1 >file。这里也分两个过程:先将fd=2复制于fd=1,而此时fd=1重定向的文件是默认的/dev/stdout,所以fd=2也重定向到/dev/stdout;之后再将fd=1重定向到file文件上。也就是说,这里的标准错误和标准输出仍然是分开输出的,只不过是使用/dev/stdout替代了/dev/stderr,使用file替代了/dev/stdout。所以,最终的结果是标准错误输出到/dev/stdout,即屏幕上,而标准输出将输出到file文件中。

可以使用下面的命令来测试2>&1 >file。第一个ls命令是正确的,结果输出到/tmp/fff.log中,第二个ls命令是错误的,结果将直接输出到屏幕上。

                                                                                                             
┌──(root💀kali)-[~]
└─# ls /boot 2>&1 >/tmp/fff.log                                                                          130 ⨯
┌──(root💀kali)-[~]
└─# ls haha 2>&1 >/tmp/fff.log
ls: cannot access 'haha': No such file or directory
                                                                                                             

最后需要说明的是一种特殊情况,如果是>&[word],且word不是一个数值,比如echo haha >&/tmp/fff.log,那么>&word&>word是等价的,都表示>word 2>&1,即标准错误和标准输出都重定向同一个目标。参考man bash的”Redirecting Standard Output and Standard Error”段落。

5. 改变当前shell环境的重定向目标

如果在命令中直接改变重定向的位置,那么命令执行结束的时候描述符会自动还原。正如上面的ls /boot 2>&1 >/tmp/fff.log命令,在ls执行结束后,fd=2还原回默认的/dev/stderr,fd=1还原回默认的/dev/stdout。

但是我们可以通过exec程序直接在当前的shell环境下改变重定向目标,只有在当前shell退出的时候才会释放描述符的绑定。


Tips:shell的内建命令exec将并不启动新的shell,而是用要被执行命令替换当前的shell进程,并且将老进程的环境清理掉,而且exec命令后的其它命令将不再执行。
不过,要注意一个例外,当exec命令来对文件描述符操作的时候,就不会替换shell,而且操作完成后,还会继续执行接下来的命令。


例如:下面的命令将标准错误fd=2指向fd=3对应的文件上。

┌──(root💀kali)-[~]
└─# exec 2>&3                                                                                            1 ⨯

因此,我们可能在一段程序执行结束后,需要将描述符还原到原来的位置,并关闭不再需要的描述符。毕竟描述符也是资源,是有限的(ulimit -n)。

6. 关闭文件描述符

  • [n]>&-
  • [n]<&-
    关闭文件描述符的方式是将[n]>&word[n]<&word中的word使用符号”-“,这表示释放fd=n描述符,且关闭其指向的文件。

7. 打开文件

[n]<> filename:打开filename,并指定其文件描述符为n,该描述符是可读、可写的描述符。若不指定n则默认为0,若filename文件不存在,则先创建filename文件。

8. 文件描述符的移动

文件描述符的移动表示将文件描述符1移动到描述符2上,同时关闭文件描述符1。

[n]>&digit-:将文件描述符digit代表的输出文件移动到n上,并关闭digit值的描述符。
[n]<&digit-:将文件描述符digit代表的输入文件移动到n上,并关闭digit值的描述符。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • Linux重定向是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说简单的我不想看到在显示器的...
    陈sir的知识图谱阅读 965评论 0 0
  • linux文件描述符:可以理解为linux跟踪打开文件,而分配的一个数字,这个数字有点类似c语言操作文件时候的句柄...
    SkTj阅读 571评论 0 1
  • 先说一下linux重定向: 0、1和2分别表示标准输入、标准输出和标准错误信息输出,可以用来指定需要重定向的标准输...
    梦归游子意阅读 1,123评论 1 2
  • 一、标准输入、输出 1. 文件描述符 (1) 定义 每打开一个文件,系统就会分配一个数字作为文件描述符来代表打开的...
    Kin丶阅读 318评论 0 1
  • 《Linux命令行与shell脚本编程大全》,4 E -- Chapter 15 一、理解输入和输出 显示脚本输出...
    生信摆渡阅读 5,085评论 0 2