Linux常用命令--管道符"|"、"xargs"、文件描述符与重定向
摘要
-
本文介绍管道符"|"与"xargs"的使用方法。
-
以及文件描述符与重定向操作符的使用方法。
-
本文基于
CentOS8(x86_64)
管道符"|"
-
管道符主要用于多重命令处理,前面命令的输出结果作为后面命令的输入
1 | # 该命令的作用就是查看文本后排序,然后再去重,最后过滤出含有hello的行并输出 |
-
以上的cat、sort、uniq、grep等命令均支持管道符,一般情况下,处理文本的命令,例如sort、uniq、grep、awk、sed等命令均支持管道,是因为这些命令均可从标准输入中读取要处理的文本(即从标准输入中读取参数)
-
而对于不是处理文本的命令,例如ls、rm、kill等则不支持从标准输入中读取参数,只支持从命令行中读取参数,而要使其也能从标准输入中读取参数则需要使用
xargs
-
命令行参数优先于标准输入即管道符,如
cat a.txt | sort b.txt
,此时sort
仅仅会处理b.txt
-
-
表示标准输入,例如cat a.txt | sort b.txt -
,相当于sort a.txt b.txt
命令行参数和标准输入的区别
- 命令行参数
命令行参数就是命令后面的参数
例如rm test.sh
,rm
是命令,test.sh
就是命令行参数 - 标准输入
标准输入一般指的是键盘输入,也可用于表示管道符之前命令的输出结果(即打印在屏幕的文本)作为之后命令的标准输入
xargs
-
xargs
的作用是接收管道符前面命令的输出进行处理后作为命令行参数传递给后续命令,而并不是作为标准输入传递给后续命令。 -
xargs
以空白字符(空格,tap,换行符均算空白字符)分隔从管道接收的文本,并且将分隔后文本均作为参数 -
xargs
常用选项
1 | 参数 解释 |
-
示例
1 | # 假设当前目录下有a.txt和b.txt,则该命令的含义就是 cat a.txt b.txt |
文件描述符
-
在 Linux 系统中,进程通过文件描述符来管理文件,文件描述符就是一个数字以及与之相关联的一堆数据
-
一个进程打开一个文件,就会创建一个新的文件描述符,这个数字一般是自增的,进程如果关闭文件,这个描述符是可以重复利用的
-
查看进程关联的文件描述符
1 | # 比如查看`mysqld`的文件描述符 |
-
每一个进程启动的时候,都会默认打开三个文件,用
0,1,2
来当做他们的描述符
1 | 0 : 标准输入文件(stdin),代表标准输入,默认指键盘输入 |
-
进程操作所有文件的过程都是一样的,都是先打开一个文件,给他一个文件描述符,然后针对这个描述符进行读或者写
-
在Linux里,键盘输入这种操作会变成一个文件操作,就类似普通的文件那样,这就是Linux的设计,一切皆是文件
-
不仅仅键盘操作和屏幕打印是文件操作,网络连接读取数据等等,也都是文件操作,这些也都会产生文件描述符
-
一个进程同时拥有的文件描述符是有上限的,这个上限可以设置。
-
我们来解读下面这个命令的执行过程
1
cat test.txt | grep "hello"
- 1.
cat
这个程序打开了test.txt这个文件,将其内容写入1
这个文件(标准输出),也就是屏幕上 - 2.管道符
|
的作用就是将前一个程序的1
(标准输出)绑定到后一个程序的0
(标准输入),这里就是将cat
的1
绑定到grep
的0
- 3.然后
grep
这个程序就试图从0
这个文件(标准输入)中读取数据,然后找到包含hello
的行,然后把找到的行写入到1
这个文件(标准输出)中,也就是屏幕上
- 1.
设置文件描述符上限
-
文件描述符上限设置分为三个限制级别:系统限制、用户限制、会话限制,最终的上限是这三个限制级别中最小的值
-
查看及设置系统上限
1 | # 查看 |
-
查看及设置用户上限
1 | # 查看 |
-
查看及设置会话上限 :默认继承自用户限制级别
1 | # 查看 |
-
文件描述符使用上限最大能设置多大呢?当然你可以把它往大了设,但是同时打开的文件描述符越多,内存开销就越大。那怎样设置一个合理的上限呢?一个经验算法是 256个fd 需4M内存。例如8G内存,
8*1024/4*256=524288
。 -
如果我们在一台机器上部署了自己的网络服务,我们只需按下面步骤修改就可以了:
1 | 1. 计算 fdmax = 物理内存大小(m为单位) / 4 * 256 ,假设内存为8G,fdmax=524288 |
重定向操作符
-
所谓重定向,其含义就是将不同的文件描述符重新定向到其它文件描述符
-
常用的重定向操作符有如下几种:
<
:将文件作为命令的标准输入
1
2cat < test.txt
mysql -uroot -p < databases.sql<<<
操作符可以在许多场景下用于将字符串作为标准输入传递给命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# 打印字符串
cat <<< "Hello World"
# 将字符串 "Hello World" 传递给 wc -c 命令,用于统计字符数
wc -c <<< "Hello World"
# 向管道命令传递字符串,将字符串 "This is a line containing the pattern" 传递给 grep 命令,用于搜索包含指定模式的行。
## 单行过滤
grep "pattern" <<< "This is a line containing the pattern"
## 多行过滤
grep Line <<< "$(printf "Line 1\nLine 2\nLine 3\n")"
# 向交互式命令传递输入,这里将字符串 "2 + 2" 传递给 bc 命令,用于进行数学计算
bc <<< "2 + 2"
## 计算了正弦函数 sin(1) 和余弦函数 cos(1) 的和
bc -l <<< "s(1) + c(1)"
# 向循环结构传递输入,printf 命令生成了一个包含换行符的字符串,并使用 <<< 将其传递给 while read 循环。read 命令会按行读取输入,并将每行赋值给变量 line。
while read -r line; do
echo "Line: $line"
done <<< "$(printf "Line 1\nLine 2\nLine 3\n")">
:将命令的输出结果输出到指定文件中,就是将标准输出重定向,且覆盖原文件内容
1
2
3
4
5
6# 以下两个命令的作用是一样的,都是将标准输出重定向到文件
cat test.txt | grep "hello" > result.txt
cat test.txt | grep "hello" 1> result.txt
# 标准输出与标准错误都重定向到文件
sh test.sh 1> run.log 2> error.log>>
:将命令的输出结果以 追加 的方式输出到指定文件中
1
2
3
4
5
6# 以下两个命令的作用是一样的,都是将标准输出重定向到文件
cat test.txt | grep "hello" >> result.txt
cat test.txt | grep "hello" 1>> result.txt
# 标准输出与标准错误都重定向到文件
sh test.sh >> run.log 2>> error.log>&
:将命令的输出结果或者一个文件描述符重新定向到另一个文件描述符
1
2
3
4
5
6
7
8
9# 以下两个命令的作用是一样的,都是将标准输出重定向到文件,标准错误重定向且等同于标准输出
cat test.txt | grep "hello" > result.txt 2>&1
cat test.txt | grep "hello" 1> result.txt 2>&1
# 标准输出重定向到文件,标准错误重定向且等同于标准输出
sh test.sh >> run.log 2>&1
# 标准输出重定向到空设备文件,也就是不输出也不显示任何信息,标准错误重定向且等同于标准输出,也就是标准错误也重定向到空设备中
sh test.sh 1>/dev/null 2>&1 -
使用重定向操作符时的注意事项
1
2
31.标准输入0、标准输出1、标准错误2 需要分别重定向,一个重定向只能改变它们其中一个。
2.文件描述符在重定向符号左侧时可以省略。
3.文件描述符与重定向符号之间不能有空格。
小贴士
我在mac系统习惯在命令行中使用code file
命令打开某个文件,但是每次使用code
命令时都会报告一个错误信息
1 | [1025/160343.890943:ERROR:codesign_util.cc(109)] SecCodeCheckValidity: Error Domain=NSOSStatusErrorDomain Code=-67062 "(null)" (-67062) |
这个错误信息表明在使用MacOS系统中的代码签名工具SecCodeCheckValidity时发生了问题,导致无法验证代码的有效性。
其实这个错误不影响使用,只是看着不美观,解决方法也很简单,在shell启动文件(例如:~/.zshrc)中加上如下配置即可
1 | # 不提示任何错误信息 |
我在网上看到其它解决方法是直接修改code的源码
,但是这个修改方式有一个问题,就是修改源码后每次升级code都会覆盖掉,所以还是直接在shell启动文件中配置一个别名来屏蔽错误信息更一劳永逸。