Linux学习笔记(十二)——数据流重定向


在Linux系统中,进程是依靠操作系统创建的。对于操作系统,进程就是一个数据结构,每个进程都有它的固有属性,比如进程号(PID)、进程状态、打开的文件等等。进程创建好之后,进程将程序载入内存空间,然后执行。

在这里插入图片描述
task_struct 就是 Linux 内核对于一个进程的描述,也可以称为「进程描述
符」。源码比较复杂,此处截取一小部分比较常见的。
其中files 指针指向一个数组,这个数组里装着所有该进程打开的文件的指针。每个进程被创建时, files 的前三位被填入默认值,分别指向标准输入 流标准输出流标准错误流。通常说的「文件描述符」就是指这个文件
指针数组的索引。一般来说,一个进程会从files[0]读取输入,将输出写入files[1],将错误信息写入files[2]。
输入重定向:把files[0]指向一个文件,那么程序就会files[0]从这个文件中读取数据,不是从键盘
输出重定向:把files[1]指向一个文件,那么程序的输出就不会写入到显示器,而是写入到这个文件中
错误重定向:把files[2]指向一个文件,那么错误信息就不会写入到显示器,而是写入到这个文件中

关于重定向

Linux 默认提供了三个特殊设备,用于终端的显示和输出,分别为stdin(标准输入,对应于在终端的输入),stdout(标准输出,对应于终端的输出),stderr(标准错误输出,对应于终端的输出)。

文件描述符设备文件说明
0/dev/stdin标准输入
1/dev/stdout标准输出
2/dev/stderr标准错误

文件描述符:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于 UNIX、Linux 这样的操作系统。
可以这样使用这些文件描述符:

# 默认使用终端的标准输入作为命令的输入,标准输出作为命令的输出
$ cat
(按Ctrl+C退出)

将 cat 的连续输出(heredoc 方式)重定向到一个文件:

$ mkdir Documents
$ cat > Documents/test.c <<EOF
#include <stdio.h>

int main()
{
    printf("hello world\n");
    return 0;
}

EOF

将一个文件作为命令的输入,标准输出作为命令的输出:

$ cat Documents/test.c

将 echo 命令通过管道传过来的数据作为 cat 命令的输入,将标准输出作为命令的输出:

$ echo 'hi' | cat

将 echo 命令的输出从默认的标准输出重定向到一个普通文件:

$ echo 'hello shiyanlou' > redirect
$ cat redirect

在这里插入图片描述
注意不要将管道和重定向混淆,管道默认是连接前一个命令的输出到下一个命令的输入,而重定向通常是需要一个文件来建立两个命令的连接

标准错误重定向

重定向标准输出到文件,这是一个很实用的操作,另一个很实用的操作是将标准错误重定向,标准输出和标准错误都被指向伪终端的屏幕显示,所以我们经常看到的一个命令的输出通常是同时包含了标准输出和标准错误的结果的。比如下面的操作:

# 使用 cat 命令同时读取两个文件,其中一个存在,另一个不存在
$ cat Documents/test.c hello.c
# 可以看到除了正确输出了前一个文件的内容,还在末尾出现了一条错误信息
# 下面我们将输出重定向到一个文件
$ cat Documents/test.c hello.c > somefile

在这里插入图片描述
这里依然出现了那条错误信息,因为标准输出和标准错误虽然都指向终端屏幕,实际它们并不一样。如果要隐藏某些错误或者警告,需要用到文件描述符:

# 将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面
$ cat Documents/test.c hello.c >somefile  2>&1
# 或者只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件
$ cat Documents/test.c hello.c &>somefilehell

注意应该在输出重定向文件描述符前加上&,否则 shell 会当做重定向到一个文件名为 1 的文件中。

在这里插入图片描述

使用tee命令同时重定向到多个文件

$ echo 'hello shiyanlou' | tee hello

在这里插入图片描述

exec命令实现永久重定向

exec命令的作用是使用指定的命令替换当前的 Shell,即使用一个进程替换当前进程,或者指定新的重定向:

# 先开启一个子 Shell
$ zsh
# 使用exec替换当前进程的重定向,将标准输出重定向到一个文件
$ exec 1>somefile
# 后面执行的命令的输出都将被重定向到文件中,直到退出当前子shell,或取消exec的重定向
$ ls
$ exit
$ cat somefile

在这里插入图片描述

创建输出文件描述符

在 Shell 中有 9 个文件描述符。可以使用下面命令查看当前 Shell 进程中打开的文件描述符:

$ cd /dev/fd/;ls -Al

使用exec命令可以创建新的文件描述符:

$ zsh
$ exec 3>somefile
# 先进入目录,再查看,否则你可能不能得到正确的结果,然后再回到上一次的目录
$ cd /dev/fd/;ls -Al;cd -
# 注意下面的命令>与&之间不应该有空格,如果有空格则会出错
$ echo "this is test" >&3
$ cat somefile
$ exit

在这里插入图片描述

关闭文件描述符

上面打开的 3 号文件描述符,可以使用如下操作将它关闭:
$ exec 3>&-
$ cd /dev/fd;ls -Al;cd -

完全屏蔽命令的输出

在 Linux 中有一个被称为“黑洞”的设备文件,所有导入它的数据都将被“吞噬”。
在类 UNIX 系统中,/dev/null,或称空设备,是一个特殊的设备文件,它通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个 EOF。

# 可以利用 /dev/null 屏蔽命令的输出
$ cat Documents/test.c 1>/dev/null 2>&1

👆这样的操作得不到任何输出结果。

使用 xargs 分割参数列表

xargs 是一条 UNIX 和类 UNIX 操作系统的常用命令。它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。

$ cut -d: -f1 < /etc/passwd | sort | xargs echo

上面这个命令用于将/etc/passwd文件按:分割取第一个字段排序后,使用echo命令生成一个列表。

练习

理解下面这段代码的作用,实际这段代码不会正常工作,分析这段代码没有正确工作的原因,并设法解决这个问题。

while read filename; do
  rm -iv $filename
done <<(ls)

这段代码想把 ls 命令的输出(当前目录的文件列表)给 rm 命令,然后使用 rm -iv 在获得你许可的情况下(输入 y),从而选择性地删除他们。
rm -iv 期待用户从标准输入给出一个 yn 的答案以确认是否删除,但标准输入被 <<(ls) 重定向了。于是 rm -iv 开始在 <<(ls) 里寻找合适的输入。如果找不到 y 或者 n 就一直寻找下去,直到把输入的内容消耗完。最后数据被消耗完了, read 读不出数据,循环也就结束了。

参考:
https://www.shiyanlou.com/courses/1/learning/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值