接七。给出上一讲没有给出的一个例子。
![](https://i-blog.csdnimg.cn/blog_migrate/551ddea192b75abf62289f096a1fb6ed.png)
上一讲讲的其实是输出重定向。今天我们来学习输入重定向。
输入重定向
上一讲已经说过/proc/pid/fd里面的0这个文件描述符对应的是标准输入,>或者1>是正确的输出,2>是错误信息,当然还有其它方式,上一讲里都有,0<,或者简写为<,就是输出的重定向符号,下面是一些例子。
![](https://i-blog.csdnimg.cn/blog_migrate/016e17e58c532a75970d9bc09578cb71.png)
第一个是发邮件的例子,需要先安装sendmai软件包和mailx。yum -y install sendmail mailx 即可。这里我试了一下,还必须要改/etc/hosts。在自己虚拟机的ip哪一行加一个主机名字加.com就可以了。效果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/71a8a46e2ee5000af32f33caf5cb7b79.png)
下面才是我们重定向的重点。如何给一个用户发邮件呢?
![](https://i-blog.csdnimg.cn/blog_migrate/b37513e98e5de8926ee85875b8d974f1.gif)
mail 用户名就可以发给它邮件了,回车输入主题,再回车输入内容,怎么结束呢?另起一行,在行头打.回车就会自动出现EOT,就停止了。然后我们mail可以查看邮件,不加-u指定用户的话是看lcl用户的邮件(当然你还要有权限看)
![](https://i-blog.csdnimg.cn/blog_migrate/9f60b4f17f053cfa33798dd9ab38675c.png)
root用户下mail -u root就可以看到刚才发给它的邮件了。左侧有一个邮件编号。在&后输入编号回车可以查看某一编号的邮件,输入q退出。上面这种是没有用到重定向的方式。
下面看一看重定向的方式:
![](https://i-blog.csdnimg.cn/blog_migrate/34a15c5bf734f5ecac954920983d902d.gif)
重定向指定的是邮件的内容,主题得自己用-s指定了,后面必须加引号的。当然主题是可以为空的,如果你用了重定向而没有指定-s,那么主题就是空的。
![](https://i-blog.csdnimg.cn/blog_migrate/dc423547efe67cde88b50fc2b268ca66.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d7c66beacb8bc0d03b4fb009f2cb68b3.png)
案例2还是来看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/e4a5cf28dc77abeab0f18b065f6ea893.gif)
cat如果你不给文件路径就按回车,效果就是输入时默认从键盘输入,然后呢,你输什么回车它会重复打出来什么,grep呢,是你输入一行回车就过滤一行。给文件路径就可以有两种方式了,一种是作为参数,也就是不加<,一种是用输入重定向,这两种方法的不同就在于参数的个数不一样,效果是一样的,不过显然完全可以不加<,这里只是举例子而已,而且我试了一下重定向的参数按esc.也可以得到。
![](https://i-blog.csdnimg.cn/blog_migrate/6553117bc4d9e800f2b7ab9684e15f41.gif)
11.txt是通过输入重定向的方式作为cat的输入的,但是esc.也可以直接调出来。
案例三还是有点意思的,先来看dd命令。
![](https://i-blog.csdnimg.cn/blog_migrate/fbcf969c4de499e3c74deefbcb15d6f2.png)
只需要能看懂案例里的命令就可以了,不需要去细究。
再来看什么叫做/dev/zero文件。参考了https://blog.csdn.net/pi9nc/article/details/18257593
![](https://i-blog.csdnimg.cn/blog_migrate/e23afc7dd567884dabf6cac21cd447c8.png)
这个命令还是有点意思的,下面就会看到。
![](https://i-blog.csdnimg.cn/blog_migrate/b5547667fb1792a0813ed2e896053fa8.png)
我们用df来看一下我们给的磁盘大小。
![](https://i-blog.csdnimg.cn/blog_migrate/e626a54224fda2c7f40db58e08a4c049.png)
当时给的是50个G,上面加起来差不多。
![](https://i-blog.csdnimg.cn/blog_migrate/7a66e57b83a4b0ee9572d65343d03d16.png)
但是呢,我们却能看到几百PB大小的文件。
![](https://i-blog.csdnimg.cn/blog_migrate/fc0e506ad72786a3a1b8805851103f3b.png)
当然这是假的,我们用了seek跳过了很多个块(block),file1.txt的真实大小只有1M,我们今天学习的重点不在于此,只是看一下。另外我们还看到dd可以测试磁盘的读写速度,804M/s。当然也可以用重定向来导入。
![](https://i-blog.csdnimg.cn/blog_migrate/167cc0ec193de8c5e1e310aa7a57f787.gif)
/dev/zero的特点就是无限输出0,如果不加count参数的节制的话,输出的文件大小会一直增加,直到把对应的分区占满,不加seek是很真实的,上面就是产生了一个1.5G的里面全是null的文件。
![](https://i-blog.csdnimg.cn/blog_migrate/7842e2c3feca90dfa9cde274dbd23c8b.png)
案例4由于需要MYSQL数据库基础,这讲我们学习的重点是输入重定向,就跳过了,想看的请到
https://www.bilibili.com/video/av18740388/?p=19,从第15分开始。
这里只是说明输入重定向还是很有用的。
![](https://i-blog.csdnimg.cn/blog_migrate/e435324061408ed41d60571fd143a241.png)
用这个命令首先要yum -y install at。参考了
https://blog.csdn.net/gxiaop/article/details/55101020
需要先启动atd的。启动的方式变了,开机自启的命令也变了。
![](https://i-blog.csdnimg.cn/blog_migrate/9575ffbeaf5d298585e21d63e73d1a01.png)
<EOT>不是打上去的,是按^D自动就有的。
![](https://i-blog.csdnimg.cn/blog_migrate/eb60bc92d11f258ee52ed54e54c3b6bb.png)
说起来有点奇怪,不知道什么时候主机名又变成localhost了。enmmmm。这个是我自己的虚拟机啊 ,,原因还真不太清楚,不管了。
![](https://i-blog.csdnimg.cn/blog_migrate/b8ba97365645e100cf2b02f8dff58c6e.png)
又三行的原因是回车并不是输入结束符,^d才是正常的输入结束符。
如果^c强制退出的话,只会把^c的上一行写入文件。
![](https://i-blog.csdnimg.cn/blog_migrate/546296e6bb8e25a0e572edcf8e3e1a12.png)
。可以用echo输入多行吗,可以,需要-e来解释转义字符。
![](https://i-blog.csdnimg.cn/blog_migrate/13a1f343fd196ce2586a497b0c3015b5.png)
但是需要引号把转义字符括起来。
![](https://i-blog.csdnimg.cn/blog_migrate/fc130f067c3ef00cde45daa3e144d4c5.png)
还有其它转义字符比如\t,一个tab键也可以这么输出。
![](https://i-blog.csdnimg.cn/blog_migrate/29eaafb785201727d9108e9cd09d3f7e.png)
这里涉及到了脚本,脚本其实也好理解的,命令是你输一行执行一行,但是脚本就可以批量执行多行,当然执行还是一行一行来,但是输入只有一次,也不需要等一行命令执行完才可以输入下一个,提高了效率,就像在IDLE里只能一次执行一段for,但是在python脚本里面可以一次写入多个同等级的for语句,MATAB也是一样。脚本里面是没有人机交互的,那么以ctrl+d作为结束符的话就不太现实,这时候需要用<<来定义结束符,上面例子已经很好的说明了这一点。
后面还会学习脚本,这里先见一下,.sh是shell脚本的后缀,就像python后缀是py,c++后缀是cpp,matlab有m文件s文件。
再补充一点:
有的时候我们写代码需要缩进,对python来说更为重要。vim里怎么缩进可以参看。
https://jingyan.baidu.com/article/1612d5008ea0b8e20e1eee81.html
就是进入可视模式然后配合<或者>,也挺简单的。
但是<<后面定义的结束符必须顶头,不顶头就会报错,而且颜色也不是棕色的,那么这个时候我们可以在<<后面加-,这个时候结束符可以不顶头,但是必须是tab键,一般我们缩进也都是tab,而不是空格。
![](https://i-blog.csdnimg.cn/blog_migrate/2637c659207124e39c85b4e88b959840.gif)
空格我试过了,确实不行,虽然eof还是棕黄色,但是确实会报错。
![](https://i-blog.csdnimg.cn/blog_migrate/4a848e7474d3989d173a786f773165d5.png)
上面这个主要还是打印这个东西,用脚本的方式打印到终端。
![](https://i-blog.csdnimg.cn/blog_migrate/37e668f8964ef704b68b3285077b6ef8.gif)
有人可能会说这么麻烦有必要吗?当然必须要这样,在没有人机交互的情况下,计算机自动执行任务的时候必须用脚本。
![](https://i-blog.csdnimg.cn/blog_migrate/4fe64520f3a662e824e18c1fda2ea321.png)
综合案例4主要是为了说明多条命令输出重定向的方法。必须是小括号,其它的都不行。
![](https://i-blog.csdnimg.cn/blog_migrate/c623ee5d534ee89926648f6ddd547f12.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f63636836e891a0a60ef85f1222722e2.png)
其实这个;蛮好理解的,在c语言,MATLAB里也都是命令分隔符也就是一行可以写多个命令,不过c语言每段代码一个;是必须的,不然会报错,MATLAB不加;会直接输出,那样会很麻烦,数据多的时候你会看到命令窗口疯狂运动。
这里先补充学习一下终端的一些基本概念。参考了
https://blog.csdn.net/lcr_happy/article/details/59484514
![](https://i-blog.csdnimg.cn/blog_migrate/b6f9e42f12decac33fb0df458428db5f.png)
/dev/ptmx是确实有的,是一个设备文件。
![](https://i-blog.csdnimg.cn/blog_migrate/f3ffccdb00cca2baaa2e01b74a77618c.png)
也就是说我们远程连接的时候用的都是伪终端。用tty可以查看当前终端,用w可以查看所有的终端,用pkill 9 -t pts/n可以终止终端,我们在虚拟机最小化安装的没有图形界面的里面的终端是tty,当然你需要登陆才行。
![](https://i-blog.csdnimg.cn/blog_migrate/888e3f05b7dabbfed58389b788be6dc8.gif)
我是没有安装图形界面,如果你安装了图形界面的话可能会出现一个:0,这个是UI界面的终端号,gdm-sessio是UI界面。
![](https://i-blog.csdnimg.cn/blog_migrate/e43c0f32e28cc91fa7a2365a836094c2.png)
我们了解到这里就可以了,我们远程连接的话都会给我们分配一个终端,当然可以用vnc连接图形界面的,我们没有UI的话就是pts/n。
匿名进程管道
![](https://i-blog.csdnimg.cn/blog_migrate/91d23d4f4bd83cf7c98a4fccf4cd3281.png)
进程管道其实也很简单,就是一个进程的输出作为另一个进程的输入,标准输入也就是1,左边进程的输出会作为右边进程的输入,中间的|就是一个匿名的管道。来看一下简单的效果。
![](https://i-blog.csdnimg.cn/blog_migrate/2d40f2f996385e6a75ed05222bbb3644.gif)
如果直接ll /dev的话是很不人性化的,因为直接给你跳到了最后,后面加一个less就可以分页查看。
如果有错的话也是会显示的。
![](https://i-blog.csdnimg.cn/blog_migrate/2c089196cdda0d9017d263e07264e063.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6d77f01910520c9ddcf6e61fff6ac016.png)
并且我们看到其实进程管道也是一种重定向,不过输出的方向对象不是文件而是进程的输入。
我们看到less的输入是一个管道pipe文件,这个文件是linux自动给你创建的。下面来看一下左边进程的文件描述符1,2会怎么样。
![](https://i-blog.csdnimg.cn/blog_migrate/9e754bd901e0ea6bfaa8e2a761aaf7b3.gif)
看到只有1重定向到了一个管道文件里面去了,说明和图上写的一样,是把标准输出也就是1重定向了,并且和less的fd里0对应的都是pipe22418,当然这种重定向也是一次性的。
![](https://i-blog.csdnimg.cn/blog_migrate/444f4398c9a09f5021c271d4d77d1b48.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ea5332d016017db66c322f40e9ca0338.png)
上面还是一些例子,grep后面呢这个匹配的表达式暂时来说加不加引号没什么区别,不过最好加上去,后面会说为什么。
![](https://i-blog.csdnimg.cn/blog_migrate/7ebbeb9e00502fe3bf2c8632d0eb9548.png)
grep后面是可以用正则表达式的,^l就是以l开头的行。rpm那么命令就是查看已经装的软件包。而yum list是查看这个源里的软件,这些软件你不一定下载了,有@的都是下载了的。
这里先来学习sort的用法,sort其实也比较简单,默认是一个一个字符去比较来进行排序的,什么意思呢?
![](https://i-blog.csdnimg.cn/blog_migrate/a1770d8e19c2fadc11b7e7d08571229b.png)
看到排序的时候1后面就是11,这是因为先按第一个字符排的话1的ascii码没有2大。
如果想按数值排序的话就需要加一个-n。
![](https://i-blog.csdnimg.cn/blog_migrate/31f280ec6b10e2a18d4937960998c7b1.png)
我们回来看案例1:
![](https://i-blog.csdnimg.cn/blog_migrate/acd31eecf9c179aa231a5be6d7768848.png)
先看一下/etc/passwd。看到以冒号分割的话,第三行列是uid,第四列是gid,第7列是所用的shell。
![](https://i-blog.csdnimg.cn/blog_migrate/b09a7a6025493905c7d5f6f5d11b83b0.png)
就按照上面的命令来打一下,上面解释的很清楚,还是很好理解的,因为/etc/passwd和多行,我们就用head看一下前10行。
![](https://i-blog.csdnimg.cn/blog_migrate/b7461ccf966e4038ad38d494c097f661.png)
再逆序看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/1d387cc5357e1db37f004f3575d35ffe.png)
分隔符默认是空格或者tab键。
![](https://i-blog.csdnimg.cn/blog_migrate/ecddc95bf48d892a9235029e0c134b50.png)
![](https://i-blog.csdnimg.cn/blog_migrate/476961bba29a036a7bbff813279d9012.png)
并且呢,sort是不会改变原来文件的内容,只是对文件内容排序然后输出而已。
也许你会用重定向改变源文件,但是不行,因为这样做的结果是清空了源文件,但是可以输出到其它文件时没有问题的。
![](https://i-blog.csdnimg.cn/blog_migrate/0b209b79de608d296a93f8965df1b5b3.png)
看到对3排序的结果可以输出到4里去,但是sort 3>3后发现3被清空了,而grep命令是会报错的,4不能同时作为输入和输出。
![](https://i-blog.csdnimg.cn/blog_migrate/75cf69235ba30d6a140271e5082c451b.png)
案例2的这行代码我们前面也见过,--sort和sort命令不同,--sort是ps的一个选项。
![](https://i-blog.csdnimg.cn/blog_migrate/76cc65e082e33e57c1d91c92840c4204.png)
当然用sort也可以完成一样的功能,--sort=-%mem就是按照内存占用降序排序。head -6的原因是表头占了一行,不过发现用|sort的时候应该是-5,因为那个标题行没有了。并且其实 | 前面都可以不加空格的。
![](https://i-blog.csdnimg.cn/blog_migrate/254fb0f6a9880961e7407eadf182b991.png)
案例3用到了awk和uniq,awk是一个比较厉害的命令,不过这里用到的是很简单的功能了。参考了
https://www.cnblogs.com/xudong-bupt/p/3721210.html
![](https://i-blog.csdnimg.cn/blog_migrate/6fa736ec944d7eeb6f6e7d57c56e9b81.png)
字段就是分隔符之间的字符而已。
![](https://i-blog.csdnimg.cn/blog_migrate/ccc8a26317e17e59926240dcd3dbbb96.png)
还有一个uniq,这个命令是去重的,不过必须是相邻的才行。
![](https://i-blog.csdnimg.cn/blog_migrate/e4e151a47d2fd88341b68966c679e810.png)
什么叫必须是相邻的呢?就是必须是相邻行才可以合并在一起的,那么这就得先排序一下了。
![](https://i-blog.csdnimg.cn/blog_migrate/30306db52db9aaa5c1d45cf248e4ba03.png)
看一下效果:
![](https://i-blog.csdnimg.cn/blog_migrate/8bc063529487aec37afacbd4cce4aba7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f300d59f3920016397e4c43e53745664.png)
案例5的话,先把有ip的行过滤出来,发现都有inet,就用这个过滤,但是发现inet6不是我们想要的行,怎么办呢,在匹配表达式后面加一个空格就可以。
![](https://i-blog.csdnimg.cn/blog_migrate/9c81a4fa6ff02628cde5bf421cefdda8.png)
这里就体现了引号的用处,如果不加引号,你在后面加空格也没用,因为根本就看不出来。
![](https://i-blog.csdnimg.cn/blog_migrate/b88d066eeee6b2521172c0119cf59c49.gif)
后面都是过滤ip的操作,后面那个/后面的数字是1的个数,其实就是掩码中1的个数,一个ip一共是有32位二进制数,最后把这个去掉就可以了。
![](https://i-blog.csdnimg.cn/blog_migrate/25da1d8e23e1b9afc39626495bbeaf23.png)
案例6的话,应该看懂是不难的。
![](https://i-blog.csdnimg.cn/blog_migrate/56685fa30c6a09f07d0265d766ebf253.png)
因为只需要根目录,所以用/$去匹配。