开发者学堂课程【Linux企业运维实战 - 入门及常用命令:Linux面试必考-IO文件重定向及管道深入讲解】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/550/detail/7606
Linux面试必考-IO文件重定向及管道深入讲解
内容介绍:
一、标准输入和输出
二、把输出和错误重新定向到文件
三、修改标准输入
I/O就是input/output,input是输入,output是输出
一、标准输入和输出
1、 程序:指令+数据
输入数据:Input
输出数据:Output
2、 打开的文件都有一个fd: file descriptor(文件描述符)
3、 Linux给程序提供三种I/O设备
标准输入(STDIN) -0 默认接受来自键盘的输入
标准输出(STDOUT) -1 默认输出到终端窗口
标准错误(STDERR) -2 默认输出到终端窗口
4、 I/O重定向: 改变默认位置
讲解:
Linux和Windows中使用的程序重要部分就两种: 程序指令和数据处理。
通过指令为了处理数据,比如读取、分析、过滤数据,从中获取希望得到的信息,所以指令是服务于数据的。而数据一般有读入和输出。
每打开一个文件,系统会随机分配一个编号,用该编号对应打开的文件,注意打开意味着是要处理的文件。该文件描述符一般为系统分配,也可以人为指定。
比如想要知道当前打开的文件是什么有哪些,输入
ll /proc/$$/fd
显示如图
这就是打开的数字对应的文件,数字就是文件描述符,也可以人为标识文件起一个文件名,比如输入ls查看有哪些文件,复制一个文件改名放在data目录下,输入
cp /etc/hosts /data/
ll /data
结果显示如图
要想打开hosts文件,打开该文件时,系统会自动分配一个文件描述符。现在人为将8表示为该文件的描述符,输入
exec 8<> /data/hosts
分配好后再来看刚才的路径,输入ll /proc/$$/fd
结果显示打开的文件文件描述符显示为8
这时用文件描述符8去访问该文件和直接访问该文件看到结果一样,输入
cat /proc/$$/fd/8
cat /data/hosts
那么能够删除8吗?输入
rm /proc/$$/fd/8
结果显示操作不允许
删除要用特殊写法,输入
exec 8>&-
cat /proc/$$/fd
ll /proc/$$/fd
结果显示该文件被删除
在上图中看到文件描述符有0、1、2,这三个常见文件描述符有特定含义。
0代表输入设备,计算机处理需要读入数据,读入数据需要把数据通过读入的输入的设备输到电脑中,而在现在我们的电脑中默认用键盘输入,键盘就是默认的标准输入设备,用0表示。
可以修改
1代表输出设备,例如ls命令输出信息是在终端窗口中显示出来的,所以标准输出设备是由终端窗口来提供该功能。
2代表标准错误,标准输出指的是正确命令,即若输入错误命令就会报错。例如输入
ls显示目录文件夹
再来输入不存在的err,输入ls /err
结果显示报错 ls: cannot access /err: No such file or directory
报错信息就为标准错误,错误信息也在终端窗口,所以也用终端窗口实现
修改键盘输入或者不在终端窗口实现标准输出或标准错误就叫重定向,重定向是改变它的默认方向
二、把输出和错误重新定向到文件
1、STDOUT和STDERR可以被重定向到文件
命令 操作符号 文件名
支持的操作符号包括:
> 把STDOUT重定向到文件
2>把STDERR重定向到文件
&>把所有输出重定向到文件
2、>文件内容会被覆盖
set -C禁止将内容覆盖已有文件,但可追加
>|file 强制覆盖
set +C允许覆盖
3、>>原有内容基础上,追加内容
讲解:
先来看标准输出的重定向:
现在有两个终端窗口,一个为/dev/pts/4,一个为/dev/pts/5,现在4上输入ls命令将其显示到5上,用到>,输入
ls > /dev/pts/5
结果不显示,打开窗口5才显示目录文件夹
也可以重定向到文件中,例如输入
ls > /data/ls.out
意味着显示的字符串信息放在该文件中,当前data下没有ls.out文件,会自动创建该文件,查看输入
cat /data/ls.out
另外实际上标准输出是通过ls 1>实现,隐藏了1
标准错误的重定向为 2>,先输入
cmd
显示错误信息bash:cmd: command not found
再来将错误信息显示到文件中,输入
cmd 2> /data/err.log
不显示结果,再来查看,输入
cat /data/err.log
结果显示刚才的错误信息
此外,想要显示曾经使用的命令放在一个文件中,输入
history > /data/cmd_list.log
如果写history 2> /data/cmd_list.log,由于history本身没有报错,那么结果还是显示正确的命令信息。
再来查看该文件内容,输入
cat /data/cmd_list.log
结果为空,说明被覆盖。
现在再来输入history > /data/cmd_list.log
显示信息后,再执行一个其他命令重定向,例如输入
who > /data/cmd_list.log
cat /data/cmd_list.log
显示内容如下
内容显示为最新的重定向命令的结果,意味着>只是覆盖,不是追加。也可以禁止覆盖,使用set -C命令,先输入
ls > ls.out
再用who命令,输入who > ls.out
再来查看,输入cat ls.out
结果显示为最新内容,现在想要禁止覆盖,输入
set -C
再来覆盖,输入w > ls.out
结果显示禁止覆盖 -bash:ls.out: cannot overwrite existing file
想要强行覆盖,使用>|,输入
w >| ls.out
cat ls.out
结果显示被覆盖内容
也可以取消禁止,使用set -C,输入
set +C
再用另种命令覆盖,输入
hostname > ls.out
要想实现追加,使用>>,例如输入
ls >> /data/cmd_list.log
cat /data/cmd_list.log
显示该文件中既有旧内容,也有新内容
追加命令也可以创建空文件,例如输入
>> f1
ll f1
若是f1文件已经存在,也不会覆盖。比touch创建空文件更加安全
思考能不能执行一个命令,既有标准输出,又有标准错误?
输入
ls显示文件夹,构建一个错误文件夹error,不存在会报错,再加上一个存在的文件夹data,data目录下可以显示出信息,输入
ls /error /data
该命令执行结果则又有对的信息,又会报错
那如果要将标准输出放在一个文件中,再将标准错误放在另一个文件中,输入
ls /error /data >f1 2>f2
该命令实现了将error放在f1中,data放在f2中,查看输入
cat f1
cat f2
显示如图
也可以将两者放在一个文件夹中,输入
ls /error /data >all.log 2>&1
是将标准错误重定向传给1,又将标准输出传给all
cat all.log
结果显示该文件中既有对又有错
但是这种方法存在问题,例如将>all.log 2>&1位置颠倒,输入
ls /error /data 2>&1 >all.log
只显示标准错误
再来查看输入
cat all.log
结果显示只有data下的标准输出
所以要注意次序问题。但是还有一种方法&省去了次序问题,输入
ls /error /data &>all.log
cat all.log
结果有标准输出有标准错误
此外,也可以加()避免次序问题,输入
(ls /error /data 2>&1 )>all.log
cat all.log
结果有标准输出也有标准错误,实际上如果不加(),ls /error /data 2>&1 >all.log中先执行标准输出>all.log,将该命令的标准输出放到all中,2重定向传给1,1代表着标准输出,标准输出默认显示在屏幕上,相当于将错误信息显示在屏幕上,正确结果放在了all中
如果使用()意味着将错误变成对的,再将对的全部重定向到all中
输入ls /error /data 2&1 2>all.log
显示结果为data的信息,再来查看all文件,输入
cat all.log
结果显示错误信息
该命令中2&1意味着将错误信息重定向到1中,2>all.log又将错误信息重定向到all中,但是结果为正确结果。因为命令中没有处理正确结果的信息,所以正确结果仍然显示在终端,但是将错误信息重定向到all中,所以all中放的是错误信息。
面试题,下列四个命令中执行效果与众不同的为:
A.cmd >log 2>71
B.cmd 2>&1 >log
C.cmd &>log
D.cmd 2>log >&2
输入ls /error /data > log1 2>&1
ls /error /data 2>&1 > log2
结果显示ls :cannot access /error:No such file or directory
ls /error /data &> log3
ls /error /data 2>log4 >&2
再来查看四个中存放的内容是否一样,输入
cat log1
cat log2
cat log3
cat log4
结果中log2中只有对的信息,其他三个既有正确信息又有错误信息
D选项代表着把对的变成错的,然后将错的放在文件中
想要将多个命令的执行结果标准输出都重定向到一个文件中,可以使用追加>>,例如输入
ls > all.log
pwd >> all.log
也可以使用(),输入(ls;pwd) > all.log
来查看输入cat all.log
在重定向时还可以用到设备/dev/null,例如执行一个命令时,不想该命令结果在屏幕上显示,可以输入 hostname > /dev/null
。如果一些脚本执行过程不想被看到,可以使用null设备,例如改口令,将wang的口令改成redhat,输入
echo redhat |passwd --stdinn wang
结果会显示改口令成功,现在要隐藏改口令的过程,可以用null设备,输入
echo redhat |passwd --stdinn wang &> /dev/null
改完口令后看不到提示
现在先创建一个软链接,输入
ln -s all.log all_link
ll all_link
思考若使用>,输入> all_link会有什么变化?
输入ll all_link没有变化,再输入ll all.log
显示all.log文件由190个字节到0个字节被清空。
all_link指向原始文件all.log,所以> all_link实际上相当于把原始文件清空
再例如输入> /dev/sda1
,再输入ll /dev/sda1,ls /boot
查看boot中的内容还在。
三、修改标准输入
有些命令例如cat需要输入信息,cat 后一般加文件,但是也可以不加文件,只输入cat,这时就会等待键盘输入,输入什么内容后回车就会将键盘输入的信息再输出,所以 cat 命令既有标准输入也有标准输出。现在想用其它来代替键盘输入,标准输入的实现方法用<,常见用文件作为标准输入设备作为键盘输入内容。例如输入
cat < /etc/hosts
就会显示该文件内容
再比如现在有这样一个f1文件,输入cd /data
ls
ll
rm -rf *
cp /etc/hosts f1
cat f1
若输入cat < f1
结果会显示文件内容,若输入cat < f1 > f2,cat f2
相当于实现文件复制的效果,若输入cat < f1 > f1
,cat f1结果显示f1文件变为0
再生成f1,输入cp /etc/hosts f1
,确认覆盖后,输入
cat < f1 >> f1
就会追加破坏原文件