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. 或许是 WebGIS 下一代的数据规范 - OGC API 系列

    目录 1. 前言 1.1. 经典的 OGC 标准回顾 1.2. 共同特点与时代变化 1.3. 免责声明 2. 什么是 OGC API 2.1. OGC API 是一个开放.动态的规范族 2.2. OG ...

  2. logrotate command in Linux

    背景 在生产过程中,由于磁盘空间.保留周期等因素,会对系统.应用等日志提出要求,要求系统日志定期进行轮转.压缩和删除,从而减少开销,而系统自带的logrotate  则是一个简单又实用的小工具,下面着 ...

  3. python3学习笔记之字符串

    字符串 1.一个个字符组成的有序的序列,是字符的集合: 2.使用单引号.双引号.三引号引住的字符序列 3.字符串是不可变对象 4.python3起,字符串就是Unicode类型: 字符串特殊举例: 不 ...

  4. C++ 练气期之函数探幽

    1. 函数基础 一个C++程序中,往往需要包含若干个函数,可以说函数是C++程序的基础组成元件,是程序中的头等公民. 如果要理解程序中使用函数的具体意义,则需要了解语言发展过程中致力要解决的 2 问题 ...

  5. Java集合容器的深度理解

    Java容器里有很多写好的容器API,这使我们很方便的可以存储.操作我们的数据. 下面是我写的容器的特点,一些容器的不同之处,从底层源码解析一下容器实现原理 一.常用的容器目录 上图可以看出,java ...

  6. Spring核心思想Ioc和Aop (面试)

    Spring核心思想Ioc和Aop (面试) 注意: Ioc和Aop并不是Spring提出的,在Spring之前就已经存在,Spring只是在技术层面给这两个思想做了非常好的实现. 1 Ioc 1.1 ...

  7. Elasticsearch-Kibana-学习笔记

    1.背景 1.1 简介 Elasticsearch 是一个分布式.高扩展.高实时的搜索与数据分析引擎.它能很方便的使大量数据具有搜索.分析和探索的能力.充分利用Elasticsearch的水平伸缩性, ...

  8. Excel 单元格的相对引用和绝对引用

    引用方式 单元格的地址由该单元格所在的行号和列标构成,一个引用代表工作表上的一个或者一组单元格,指明公式中数据所在的位置. 编号 消费记录 价格 1 乒乓球 1 2 火腿肠 2 3 乒乓球 1 4 羽 ...

  9. StarRocks 运维工具 StarGo

    注:本文主要内容均来源 StarRocks 官网 https://docs.starrocks.com/zh-cn/main/administration/stargo StarGo 是一个用于管理多 ...

  10. CF914G Sum the Fibonacci (快速沃尔什变换FWT + 子集卷积)

    题面 题解 这是一道FWT和子集卷积的应用题. 我们先设 cnt[x] 表示 Si = x 的 i 的数量,那么 这里的Nab[x]指满足条件的 Sa|Sb=x.Sa&Sb=0 的(a,b)二 ...