标准 I/O 流
Linux shell 可以接收和发送字符序列或字符流形式的输入和输出。无论实际的字符流是来自还是来自文件,键盘,显示器上的窗口或其他IO设备,字符流都可以通过文件IO技术进行访问。Linux shell 使用3种标准的I/O流,每种流都与一个文件描述符。Linux 内核采用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
1 | stdout //标准输出流,它显示命令运行的输出,文件描述符为 1 |
输入流通常通过终端敲击键盘为程序提供输入。输出流通常向终端输出显示文本字符。
重定向
在Linux命令行模式中,如果命令所需的输入不是来自键盘,而是来自指定的文件,这就是输入重定向。同理,命令的输出也可以不显示在屏幕上,而是写入到指定文件中,这就是输出重定向。
> 符号
格式 {stdout|stderr} > filename
,使用 >
符号将左侧输出重定向到一个文件中。需要注意的是:如果文件名不存在则创建它,如果存在则覆盖。
1 | ➜ echo "hello" > a.txt |
还可以这样:
1 | ➜ ls | grep "**.png" > a.txt |
该命令将左侧命令的标准输出重定向到a.txt
文件中。
特别的,使用 /dev/null
可以清空文件。/dev/null
相当于Linux的黑洞文件,永远为空。
1 | cat /dev/null > a.txt |
>> 符号
格式 {stdout|stderr} >> filename
,>>
符号和>
符号作用差不多,如果文件不存在则创建,存在则追加内容到文件尾,不会覆盖。
1 | ➜ cat a.txt |
< 符号
格式 {command} < filename
,将文件的内容作为标准输入,传给左边的命令处理。
如下,将字符 o
替换为 x
,但是源文件并不会改动:
1 | ➜ tr 'o' 'x' < a.txt |
又比如使用 nc
命令传输文件,发送端将文件作为标准输入传输给接受端,再由接收端写入文件。
1 | nc -l {port} > filename // 接收端 |
管道
管道命令操作符:|
,它能将前面一个命令传出的标准输出(stdout),作为标准输入(stdin)传给下一条命令。相比于重定向,管道符号两边都是可独立执行的命令,通常用于命令间传递参数,而重定位符号的右侧必须是文件名。
如下这条命令 ls
列出当前目录下所有非隐藏文件,作为标准输入传给 grep
去过滤出以 .png
结尾的文件:
1 | ➜ ls | grep "**.png" |
参数传递
假设现在我启动了一个 Java 进程。
1 | ➜ ps -ef | grep java |
执行这条命令后终端打印出 Java 进程信息,进程号 6292。接下来我想结合管道命令 kill
掉这个 Java 进程。
1 | ➜ ps -ef | grep java | grep -v grep | awk '{print $2}' | xargs kill -9 |
这个命令看上去很长其实无非是多个命令组合在一起。我之所以想说这个是因为在Tomcat的运行脚本catalina.sh
中看到了用于停止Tomcat的类似的命令。
1 | ➜ ps -ef | grep java | grep -v grep | awk '{print $2}' | xargs kill -9 |
ps -ef
列出所有进程传递给grep java
过滤出包含 Java 关键字的进程,再传递给grep -v grep
剔除包含grep关键字的进程,awk '{print $2}'
6292,再将参数传递给xargs kill -9
最终杀掉进程。实际上等同于执行了 kill -9 6292
。
很多时候比如说再写shell脚本时确实这样用,因为进程号是动态分配的,不能写死,只能通过一些手段动态获取进程号再进行参数传递。
命令替换
另外简单提一下命令替换。在Linux命令行模式下,当遇到一对 `` 时,将首先执行 ` 中间包含的命令,然后将其输出结果作为参数代入命令行中,这就是命令替换了。它将一个命令的输出作为另外一个命令的参数
过滤出.*rc
的文件,将文件中的内容统一输出到rc.txt
中
1 | ➜ cat `ls -a | grep ".*rc"` > ./Desktop/rc.txt |
上诉命令和下面这条起一个作用
1 | ➜ ls -a | grep ".*rc" | xargs cat > ./Desktop/rc.txt |