Linux 重定向和管道

重定向

在计算机技术中,重定向的意思是更改数据流的方向或目标,在Linux系统中,重定向常用于控制命令的输入和输出。

在Linux操作系统中有三种预定义的数据流,分别是标准输出(sedout)、标准输入(stdin)和标准错误(stderr)。用户通过这三种预定义的数据流来和进程进行交互。

  • 标准输入 (stdin):当程序需要输入时(例如,需要用户提供数据),默认会从标准输入读取。在命令行环境中,这通常意味着从用户的键盘获取输入。

  • 标准输出 (stdout):程序的主要输出通过此流发送给用户。例如,当用户执行一个查询或请求操作的结果时,这些结果会通过标准输出显示。

  • 标准错误 (stderr):与标准输出分开,这个流专门用于显示错误消息或警告。这使得用户可以容易地区分常规输出和可能需要特别关注的问题或错误。

在Linux中,标准输入 (stdin)对应文件描述符0,标准输出 (stdout)对应文件描述符1,标准错误 (stderr)对应文件描述符2。

文件描述符:

文件描述符是一个非负整数,每打开一个文件,系统就会分配一个唯一的数字代表目前打开的文件或者资源。可以理解为一个指向文件的指针,通过文件描述符,操作系统可以追踪和识别打开的文件,以便进行读取、写入、定位和其他操作。

单个进程在默认情况下会限制打开文件的数量,也就是当一个进程达到了其文件描述符数量的最大限制时,再打开新文件就会提示失败了。这个时候就可以通过ullmit或者修改配置文件的方式来增加文件描述符的数量了。

# 临时生效
ulimit -n number

# 持久生效
 vim /etc/security/limits.conf
# <username>  [hard|soft] nofile  <new_limit>
	# <username>:表示对谁进行显示,*表示所有用户
	# soft:软限制,超过了只是警告
	# hard:硬限制,超过了就没法继续打开文件了
	# <new_limit>:希望设置的新的文件描述符数量限制 unlimited表示无限

image

在Linux中,文件描述符 0 与标准输入(stdin)关联,在Linux中一切皆文件,stdin对应/dev/stdin这个文件,stdin代表的是当前终端或shell的输入,同理stdout和/dev/stdout关联,stderr和/dev/stderr关联。/dev/stdout 和 /dev/stderr 分别对应于当前终端或shell的输出和错误输出。所以可以通过重定向符号来改变文件的标注输入和输出等。

  • 标准输入重定向使用 1> 符号表示

  • 标准输出重定向使用 < 符号表示

  • 标准错误重定向使用 2> 表示

重定向的应用:

例如:将输出到屏幕的内容重定向到文件

echo "12345" > 1.txt
# 将输出到屏幕上的内容通过标准输入重定向符号(>)重定向到1.tct这个文件中去。

例如:同时将标准输出和标准错误都输出到不同文件中

output 1> file1  2> file2 

例如:将标准输出和标准错误都输出到同一文件中

output 1> file_name 2>&1

# 简写方法
outpu &> file_name

说明:
(1)将标准输出和标准错误都输出到同一文件中可以简写为(&> 或者 >&)符号。即:outpu &> file_name

(2)表示将标准输出重定向到file_name这个文件中,2>&1表示把标准错误重定向到标准输出里面。 &符号的作用是表示1是描述符不是文件名1

(3)标准输出和标准错误都输出到同一文件中时,前后次序有要求。需要先放对的 再放错的

错误范例:

output  2>&1 > file.txt

这样写不对,因为首先执行的就是将标准错误重定向到标准输出对应的文件里面,但是此时标准输出也不知道自己应该重定向到哪个文件,故会将内容输出到屏幕,最后就没有实现标准输出和标准错误的重定向。

管道

在Linux中,管道是一种通信机制,即允许两个或多个进程之间的数据传输和通信,将一个进程的输出作为另一个进程的输入。因为这种行为和水管类似,就像水通过水管从一端流向另一端。

管道有以下特性:

  1. 管道使用先进先出(FIFO)的方式传递数据。一个进程将数据写入管道的写入端,另一个进程从管道的读取端读取数据,确保数据按照写入的顺序被读取。

  2. 管道是一种半双工通信机制,在同一时间只能有一端进行写入或读取操作。不能同时进行写入和读取。

  3. 当管道为空时,读取操作会被阻塞,直到有数据可读。当管道写满时,写入操作会被阻塞,直到有空间可以写入。

  4. 管道是基于内存的通信机制,数据在内存中进行传递,仅适用于在同一台机器上运行的进程之间的通信。

  5. 管道的写入端和读取端分别与两个进程相关联,一个进程将数据写入管道的写入端,另一个进程从管道的读取端读取数据。这样可以将一个进程的输出连接到另一个进程的输入,实现数据流的通道。

进程间通信

首先我们需要连接为什么进程间的通信会使用到管道这种机制,首先理解什么是进程,进程就是计算机中运行的程序的实例,即进程就是一个程序的运行过程,进程是操作系统最核心的概念,运行程序的运行过程很复杂,所以为了方便交流,就给一个程序的运行过程取了个名字,叫做进程。

进程有一种特性叫作隔离性,即每个进程都是相互独立的执行实体,它们在内存中拥有独立的地址空间。进程的执行不会相互干扰,例如给A进程分配了一块内存空间,这块内存空间中的资源只有进程A才能看到,其它进程是无法使用的。

所以进程之间要通信,就需要借助共享内存或者管道来实现了,共享内存是所有进程都能读取和写入数据的内存空间(默认情况下进程之间的内存空间是隔离的),进程可以直接读取和写入共享内存区域中的数据,所以进程之间的通信可以通过共享内存来实现;
管道的话和共享内存一样,也是进程间通信的一种机制,通过创建一个单向的数据流通道来实现进程间的通信。

在Linux中,管道分为两种类型,有名管道和无名管道

  • 无名管道:用于在具有亲缘关系的父子进程之间通信

  • 有名管道:可以在任意两个进程之间通信

匿名管道
在Linux中,| 管道符实际上是一种通过Shell解释器创建的匿名管道的简便表示方式。这种匿名管道用于在具有亲缘关系的父子进程之间进行通信。

匿名管道工作流程:

  1. shell解释器会根据相关的系统调用创建一个匿名管道。

  2. 在管道符左右端的命令会作为shell进程的两个子进程来运行

  3. 左边的命令将输出的内容写入管道的写入端

  4. 因为管道是shell解释器创建的匿名管道,匿名管道是用于在具有亲缘关系的父子进程之间通信,所以匿名管道写入端的数据,可以被管道符右边的命令读取

匿名管道的使用:

cat /etc/passwd | wc -l

image

  1. 虽然 cat 和 wc 不具备直接的亲缘关系,但是它们通过 Shell 解释器创建的管道实现了间接的通信。

  2. 当执行这个命令时,Shell 解释器会先创建一个管道,并在父进程中创建两个子进程,一个执行 cat /etc/passwd,另一个执行 wc -l。这两个子进程通过管道进行通信。

  3. cat 命令将 /etc/passwd 文件的内容写入管道的写入端,而 wc 命令从管道的读取端读取数据并进行行数统计。这样,通过管道连接的命令之间就建立了数据传递的关系,实现了间接的进程间通信。

有名管道:
创建有名管道

mkfifo pipe_name

说明:创建的这个有名管道是存在于内存中的,作为进程间通信的一个缓冲区

使用场景:

  • 匿名管道:匿名管道在需要时自动创建,并在不再使用时被删除。需要在单个命令或脚本中的进程之间传递数据,并且不需要维护持久性连接时,匿名管道很有用

  • 有名管道:需要在进程之间长时间保持一个持久的连接时,使用有名管道很有用。有名管道在创建时有一个唯一的名称,并可由多个进程用来发送和接收数据。即多个进程需要在很长一段时间内相互通信。

管道特性说明

因为管道具有先进先出、从输入端存入数据,就需要从输出端将数据读出来,然后才可以进行下一次存取和读取。
image

存入管道的数据被读取后,就解除了阻塞的状态。
image

如果管道里面没数据,读取也会进入阻塞状态
image

所以往管道文件里面放入一段内容,没人取则会阻塞,这样就只能实现统一时间,只能放一个数据进去,要的你感到输出端把数据读取后才能再放另一个数据进去;

posted on 2022-06-11 16:55  背对背依靠  阅读(88)  评论(0编辑  收藏  举报