java -jar snapshot.jar > snapshot.log 2>&1 &

写Java的朋友一定对上面的命令很熟悉,相信大部分人都知道>表示的是重定向,那么什么是重定向?2>&1又是什么意思?

要从根儿上说明这个问题,我们有必要好好理解一下「文件描述符」的概念。

1. 文件描述符

1.1. 什么是文件描述符

文件描述符(File descripter)就是一个整数,这个整数唯一标识了操作系统中某个被打开的“文件”。

1.2. 文件与I/O

说到“文件”必然离不开I/O。

很多人搞不明白I/O到底应该怎么理解,字面上就是输入/输出罢了,但是站在不同角度,其表示的含义也不一样。

站在计算机的角度,I/O表示的是计算机与外界的交互,交互的对象是硬件设备,输入输出自然也指的是和硬件之间的输入输出。

站在程序的角度,I/O的含义更宽泛,操作系统与所有能被当作文件的对象之间的交互就是I/O。

Linux的哲学思想是「一切皆文件」,文件(file,例如foo.txt)、管道(pipe)、网络(socket),甚至打印机、显示器、磁盘以及命令行(terminal)都算是文件。

文件描述符标识的就是这些文件。

文件描述符这个术语通常出现在Unix或类Unix系统中,比如Linux、MacOS以及BSD等。

在Windows系统中,他有另外一个响当当(或者臭名昭著)的名字——句柄(File handle)。

2. 文件描述符原理

2.1. 进程私有文件描述符表

每个进程可以打开多个文件,所以每个进程都会有一个私有的文件描述符表(file descriptors table)。

注:下文称file descriptors table中的每一个条目为file descriptor,称file descriptor中的整数为fd

需要注意的是,每个进程的fd 012已经被占用(下文会有解释),之后分配的每个进程的fd3开始。

进程级的描述符表的每一个条目记录了当前进程所有打开的文件的文件描述符,进程之间相互独立,例如一个进程使用了文件描述符99,另一个进程也可以用99

fd只是个数字而已,操作系统肯定需要根据这个数字来找到实际对应的文件。换句话说,file descripter肯定指向了某个表示真实文件的数据结构,或者能够再次根据这个数据结构来找到真实文件。

这个数据结构就是「全局文件表」。

2.2. 全局文件表

全局文件表(global file table),顾名思义,就是所有进程共享的一个数据结构。

当用户进程向内核发起一个针对文件的system call(比如open())时,内核将

  1. 允许进程访问;
  2. 向全局文件表(global file table)中插入一个条目,并向进程返回一个指向该条目的一个file descriptor
  3. 进程将file descriptor插入到file descriptors table,并返回其在file descriptors table中的下标,也就是fd

其实,根据global file table并不能直接找到对应文件进行操作,还需要根据其中的指针找到inode table的数据结构,进而再找到最终文件。但是这个技术细节对我们认识文件描述符没有什么作用,于是按下不表了。

2.3. 为什么需要文件描述符

进程进行系统调用的时候,内核为什么不直接返回指向文件的指针呢?反而多此一举加了个fd来引用文件。

原因是为了防止用户空间的程序随意读写操作系统内核的文件对象

如果内核直接返回内核中文件对象的地址给进程,进程便可以绕过内核,肆意对该文件进行操作,这样一来用户空间和内核空间的划分便如同虚设。

有了文件描述符之后,由于global file table处于内核空间中,用户即使拥有fd,也无法得到实际文件对象的地址,除非把fd作为系统调用的参数来使用,如此一来,控制权又回到了内核手中,也便达到了权限控制的目的。

3. 标准输入/标准输出/标准错误

前面说到,进程的文件描述符表的前3项已经被默认使用了。

  • 0:标准输入(stdin)
  • 1:标准输出(stdout)
  • 2:标准错误(stderr)

这些名词怎么理解?

我们在Java中使用new Scanner(System.in)接收从键盘的输入,使用System.out.println()向显示器写数据,对应C语言分别是scanf()printf()

需要明确的是,函数并非直接使用键盘和显示器,而是使用了标准输入和标准输出

说得再通俗一点就是,进程生来就有一个耳朵和两张嘴,耳朵用来接受标准输入里的数据,一个嘴往标准输出里边“说话”,另一张嘴往标准错误里边“吐槽”。

函数并不知道数据从哪里来,也不关心数据要到哪里去,它们只需要从标准输入读数据,向标准输出标准错误中写数据就行了。

这就是抽象啊,朋友们!

默认情况下,操作系统会把所有键盘输入都发送到标准输入,会把从标准输出标准错误中读到数据发送到显示器。

为了方便表示,下文不再将全局文件表画出,而是用一张表来简化表示文件描述符和数据流之间的对应关系。

接下来我们就可以解释文章开头提的问题了。

4. 输入输出重定向

标准输入/输出/错误在描述表的位置虽然是固定的,但他们指向的数据流是可以改变的。

java -jar snapshot.jar > snapshot.log 2>&1 &

这条指令的意思就是将snapshot.jar程序用>运算符重定向标准输出,由原本的指向显示器改为snapshot.log文件。

2>是用来重定向标准错误,因为标准错误在描述符表中的fd就是2,同样,其实重定向标准输出也可以表示为1>,不过一般简写为>

标准错误标准输出可以重定向到同一个地方,比如指令中的&1表示的就是标准输出2>&1的含义就是重定向标准错误到标准输出表示的数据流中。


完!

2>&1到底是什么意思?的更多相关文章

  1. 拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?

    写在前面 除了博文内容之外,和 netfocus 兄的讨论,也可以让你学到很多(至少我是这样),不要错过哦. 阅读目录: 迷雾森林 找回自我 开源地址 后记 毫无疑问,领域驱动设计的核心是领域模型,领 ...

  2. Js new到底发生了什么

    在Js中,我们使用了new关键字来进行实例化 那么在这个new的过程中到底发生了什么? 关于构造函数的return 正常来讲构造函数中是不用写return语句的,因为它会默认返回新创建的对象. 但是, ...

  3. 电信计费业务:预后融合OCS到底应该实扣还是虚扣?

    引入OCS的初衷之一是为了让计费系统能够参与到用户的通讯控制中来,也就是所谓的实时信控.用户在没有余额时,通讯就会被停止,不会造成"天价欠费 ",一方面保障用户的利益,一方面也保障 ...

  4. 港真,到底应该选择OA还是BPM?

    越来越多企业意识到流程管理的重要性,但是,选择OA还是BPM,却让他们产生了选择困难症. 一方面,企业皆注重流程的高效运转,最好内外部的业务都能用一个系统来解决.所有流程一天就能上线什么的,那就更好啦 ...

  5. 四、可空类型Nullable<T>到底是什么鬼

    值类型为什么不可以为空 首先我们都知道引用类型默认值都是null,而值类型的默认值都有非null. 为什么引用类型可以为空?因为引用类型变量都是保存一个对象的地址引用(就像一个url对应一个页面),而 ...

  6. 在开发中到底要不要用var?

    var是.net的一个语法糖,在Resharper中推荐都使用这个关键字,平常我也是经常用:但是在跟其他程序员推广使用时,他的一些考虑引发了我的深思,到底该不该使用这个关键字呢? 我使用的理由 我使用 ...

  7. 阿里的weex框架到底是什么

    title: 阿里的weex框架到底是什么 date: 2016-09-27 10:22:34 tags: vue, weex category: 技术总结 --- weex 工作原理 首先看下官方的 ...

  8. 全局变量 HInstance 到底是在什么时候赋值的?

    在学习 资源文件 和 钩子函数 时, 经常用到当前模块句柄(HInstance)这个全局变量. 今天特别想知道, 它到底是在什么时候给赋值的. 输入 HInstance; "Ctrl+鼠标& ...

  9. 从问题看本质:socket到底是什么?

    一.问题的引入——socket的引入是为了解决不同计算机间进程间通信的问题 1.socket与进程的关系 1).socket与进程间的关系:socket   用来让一个进程和其他的进程互通信息(IPC ...

  10. char varchar nchar nvarcharar到底有多大区别

    首先说明下,ASP.NET MVC系列还在龟速翻译中. 工作好多年,基础知识甚是薄弱,决定以后在coding(cv操作)的时候尽量多google下,然后总结下来,目的有三:     1. 加深自己的理 ...

随机推荐

  1. ooday03 Java_引用类型数组_继承_super_向上造型

    引用类型数组: 点击查看代码 1)Bomb[] bs = new Bomb[3]; bs[0] = new Bomb(100,200); bs[1] = new Bomb(200,300); bs[2 ...

  2. 【C++】从设计原理来看string类

    1.一些C++基础知识 模板类string的设计属于底层,其中运用到了很多C++的编程技巧,比如模板.迭代器.友元.函数和运算符重载.内联等等,为了便于后续理解string类,这里先对涉及到的概念做个 ...

  3. 日志审计与分析实验三(rsyslog服务器端和客户端配置)(Linux日志收集)

    Linux日志收集 一.实验目的: 1.掌握rsyslog配置方法 2.配置rsyslog服务收集其他Linux服务器日志: C/S架构:客户端将其日志上传到服务器端,通过对服务器端日志的查询,来实现 ...

  4. 渲染优化中那些奇奇怪怪的rules

    禁⽌使⽤ iframe iframe 会阻塞主⻚⾯的 Onload 事件 搜索引擎的检索程序⽆法解读这种⻚⾯,不利于 SEO iframe 和主⻚⾯共享连接池,⽽浏览器对相同域的连接有限制,所以会影响 ...

  5. go-zero单体服务使用泛型简化注册Handler路由

    一.Golang环境安装及配置Go Module https://go-zero.dev/cn/docs/prepare/golang-install mac OS安装Go# 下载并安装Go for ...

  6. Mysql 数据恢复流程 基于binlog redolog undolog

    注:文中有个易混淆的地方 sql事务,即每次数据库操作生成的事务,这个事务trx_id只在undolog里存储,同时undolog维护了此事务是否完成的状态. 日志持久化事务,为了保证redolog和 ...

  7. python 执行需要管理员权限的命令(Windows)

    由于Windows存在管理员权限限制,执行需管理员权限的命令时会出错, 有两种方案, 1.采用python调用vbs文件,vbs调用bat文件 2.采用提供弹出用户管理员权限方式让用户确认 1.采用p ...

  8. AI全流程开发难题破解之钥

    摘要:通过对ModelArts.盘古大模型.ModelBox产品技术的解读,帮助开发者更好的了解AI开发生产线. 本文分享自华为云社区<[大厂内参]第16期:华为云AI开发生产线,破解AI全流程 ...

  9. 如何仿造websocket请求?

    之前两次singnalr. websocket实时推送相关: .NET WebSockets 核心原理初体验 SignalR 从开发到生产部署避坑指南 tag: 浏览器--->nginx--&g ...

  10. Apache SeaTunnel (Incubating) 2.1.0 发布,内核重构、全面支持 Flink

    2021 年 12 月 9 日,SeaTunnel (原名 Waterdrop) 成功加入 Apache 孵化器,进入孵化器后,SeaTunnel 社区花费了大量时间来梳理整个项目的外部依赖以确保整个 ...