选择特殊符号
选择搜索类型
请输入搜索
BFS 是一个进程调度器,可以解释为"脑残调度器"。这古怪的名字有多重含义,比较容易被接受的一个说法为:它如此简单,却如此出色,这会让人对自己的思维能力产生怀疑。
BFS 不会被合并进入 Linus 维护的 Linux mainline,BFS 本身也不打算这么做。但 BFS 拥有众多的拥趸,这只有一个原因:BFS 非常出色,它让用户的桌面环境达到了前所未有的流畅。在硬件越来越先进,系统却依然常显得迟钝的时代,这实在让人兴奋。
进入 2010 年,Android 开发一个分支使用 BFS 作为其操作系统的标准调度器,这也证明了 BFS 的价值。后来放弃。
调度器是非常复杂的话题,尤其是 CFS 调度器,想要描述清楚,需要一支非凡的笔,我还没有找到。但 BFS 非常简单,所以我才有勇气在这里写点儿 BFS 的实现原理什么的。首先介绍几个关键概念。
虚拟 Deadline ( Virtual Deadline )
当一个进程被创建时,它被赋予一个固定的时间片,和一个虚拟 Deadline。该虚拟 deadline 的计算公式非常简单:
Virtual Deadline = jiffies + (user_priority * rr_interval) 公式一 |
其中 jiffies 是当前时间 , user_priority 是进程的优先级,rr_interval 代表 round-robin interval,近似于一个进程必须被调度的最后期限,所谓 Deadline 么。不过在这个 Deadline 之前还有一个形容词为 Virtual,因此这个 Deadline 只是表达一种愿望而已,并非很多领导们常说的那种 deadline。
虚拟 Deadline 将用于调度器的 picknext 决策,这将在后续章节详细描述。
进程队列的表示方法和调度策略
在操作系统内部,所有的 Ready 进程都被存放在进程队列中,调度器从进程队列中选取下一个被调度的进程。因此如何设计进程队列是我们研究调度器的一个重要话题。BFS 采用了非常传统的进程队列表示方法,即 bitmap 加 queue。
BFS 将所有进程分成 4 类,分别表示不同的调度策略 :
Realtime,实时进程 SCHED_ISO,isochronous 进程,用于交互式任务 SCHED_NORMAL,普通进程 SCHED_IDELPRO,低优先级任务 实时进程总能获得 CPU,采用 Round Robin 或者 FIFO 的方法来选择同样优先级的实时进程。他们需要 superuser 的权限,通常限于那些占用 CPU 时间不多却非常在乎 Latency 的进程。
SCHED_ISO 在主流内核中至今仍未实现,Con 早在 2003 年就提出了这个 patch,但一直无法进入主流内核,这种调度策略是为了那些 near-realtime 的进程设计的。如前所述,实时进程需要用户有 superuser 的权限,这类进程能够独占 CPU,因此只有很少的进程可以被配置为实时进程。对于那些对交互性要求比较高的,又无法成为实时进程的进程,BFS 将采用 SCHED_ISO,这些进程能够抢占 SCHED_NORMAL 进程。他们的优先级比 SCHED_NORMAL 高,但又低于实时进程。此外当 SCHED_ISO 进程占用 CPU 时间达到一定限度后,会被降级为 SCHED_NORMAL,防止其独占整个系统资源。
SCHED_NORMAL 类似于主流调度器 CFS 中的 SCHED_OTHER,是基本的分时调度策略。
SCHED_IDELPRO 类似于 CFS 中的 SCHED_IDLE,即只有当 CPU 即将处于 IDLE 状态时才被调度的进程。
在这些不同的调度策略中,实时进程分成 100 个不同的优先级,加上其他三个调度策略,一共有 103 个不 同的进程类型。对于每个进程类型,系统中都有可能有多个进程同时 Ready,比如很可能有两个优先级为 10 的 RT 进程同时 Ready,所以对于每个类型,还需要一个队列来存储属于该类型的 ready 进程。
BFS 用 103 个 bitmap 来表示是否有相应类型的进程准备进行调度。如图所示:
当任何一种类型的进程队列非空时,即存在 Ready 进程时,相应的 bitmap 位被设置为 1。
调度器如何在这样一个 bitmap 加 queue 的复杂结构中选择下一个被调度的进程的问题被称为 Task Selection 或者 pick next。
Task Selection i.e. Pick Next
当调度器决定进行进程调度的时候,BFS 将按照下面的原则来进行任务的选择:
首先查看 bitmap 是否有置位的比特。比如上图,对应于 SCHED_NORMAL 的 bit 被置位,表明有类型为 SCHED_NORMAL 的进程 ready。如果有 SCHED_ISO 或者 RT task 的比特被置位,则优先处理他们。
选定了相应的 bit 位之后,便需要遍历其相应的子队列。假如是一个 RT 进程的子队列,则选取其中的第一个进程。如果是其他的队列,那么就采用 EEVDF 算法来选取合适的进程。
EEVDF,即 earliest eligible virtual deadline first。BFS 将遍历该子队列,一个双向列表,比较队列中的每一个进程的 Virtual Deadline 值,找到最小的那个。最坏情况下,这是一个 O(n) 的算法,即需要遍历整个双向列表,假如其中有 n 个进程,就需要进行 n 此读取和比较。
但实际上,往往不需要遍历整个 n 个进程,这是因为 BFS 还有这样一个搜索条件:
当某个进程的 Virtual Deadline 小于当前的 jiffies 值时,直接返回该进程。并将其从就绪队列中删除,下次再 insert 时会放到队列的尾部,从而保证每个进程都有可能被选中,而不会出现饥饿现象。
这条规则对应于这样一种情况,即进程已经睡眠了比较长的时间,以至于已经睡过了它的 Virtual Deadline,
T1 本来的 virtual deadline 为 t1,它 sleep 之后,其他的进程比如 T2 开始运行,等到 T1 再次 wakeup 的时候,当时的 jiffies 已经大于 t1,在这种情况下,T1 无需和其他进程的 virtual deadline 相比较,而直接被 BFS 调度器选取。
三个基本的 scenario 可以概括多数的调度情景。系统中发生的每一次调度都属于以下三种情景之一。
进程wakeup:TaskInsertion
睡眠进程 wakeup 时,调度器需要执行 task insertion 的操作,将该进程插入到 run queue 中。BFS 将进程插入相应队列的操作就是执行一个双向队列的插入操作,计算机常用算法结构告诉我们,这个操作是 O(1) 的。不过,BFS 在执行插入操作之前需要首先查看当前进程是否可以抢占当前正在系统中运行的进程。因此它会用新进程的 virtual deadline 值和当前在每个 CPU 上正在运行的进程的 virtual deadline 值进行比较,如果新进程的值小,则直接抢占该 CPU 上正在运行的进程。这个算法是 O(m) 的,其中 m 是 CPU 的个数,假如系统中有 16 个 CPU,那么每次都需要进行 16 次比较。但这个设计却保证了非常好的 low-latency 特性。
进程Sleep
当前正在运行的进程有可能主动睡眠,此时,调度器需要将该进程从 run queue 中移除,并选择另外一个进程运行。但该进程的 virtual deadline 的值保持不变。
这样该进程 wakeup 时,其 virtual deadline 将相对较小,因为 jiffies 随着时间流逝而不断增加。较小的 Virtual Deadline 可以保证该进程能更快得到调度。
仍然以图 8 为例,系统中有两个进程,T1 和 T2,T1 进入 sleep 状态后其 virtual deadline 仍然为 t1。T2 此时被调度,根据公式一,计算得出其 virtual deadline 为 t2。此后,T1 进程 wakeup 了,此时虽然 T2 的时间片尚未用完,但由于 T1 的 virtual deadline 小于 T2 的,(t1<t2),因此 T1 立即得到调度。
进程用完自己的时间片
每个进程都拥有自己的时间片,即使不被其他进程抢占,假如属于自己的时间片用完时,当前进程也一定会被剥夺 CPU 时间,以便让别的进程有机会执行。
当前进程的时间片用完后就必须让出 CPU, 此时将它的 virtual deadline 按照公式一重新计算。
这保证了一个特性:只有其他就绪进程都获得 CPU 之后,用完当前时间片的进程才可以再次得到运行,这避免了饥饿。
linux调度器(BFS )是一款专门为 Linux 桌面环境所设计的内核调度器,它基于 Staircase Deadline和 EEVDF 算法,支持 Linux 2.6.31之后的内核。它提供了前所未有的流畅桌面性能,不仅得到了用户的认可,也为一些商业系统所采用。
一、执行步骤:1.以root身份登录2.查看系统时间(date)和系统bios时间(hwclock或/sbin/hwclock)3.在/usr/sbin下,使用命令 ntpdate ...
LPI 作为国内外知名的Linux认证机构,长期受IBM、google、hp、腾讯等国内外知名企业委托招聘Linux工程师,同时LPIC Level 2证书获得者大都供职于以上企业。Novell对所有...
inux中文件查找命令有很多,一般文件分类为两种,一种是应用程序,即二进制文件,一种是文档,即文本文件。对于前者,我们一般使用whereis、which等命令,对于后者,我们习惯使用find命令,当然...
BFS vs CFS,设计上的不同 白天 Con Kolivas 在医院里当麻醉师,为人们解除痛苦,业余的时候借 Linux 解除自己的痛苦。额,Kolivas 学习 Linux 并不是为了解决痛苦,我臆测而已。但据 Kolivas 自述,他接触 Linux 内核时连 C 语言也没有学习过。。。这个事实证明,语言只是一项工具,对问题本质的深入理解才是写程序的关键。可能还有执着,CFS 和 RSDL 之争导致 Kolivas 离开 Linux 社区,此去经年,当 Kolivas 再次开始看内核代码的时候,他立即发现 CFS 存在以下几个设计上的问题:
CFS 的目标是支持从桌面到高端服务器的所有应用场景,这种大而全的设计思路导致其必须做一些实现上的折中,此外,那些只有在高端机器中才需要的特性将引入不必要的复杂代码。
其次,为了维护多 CPU 上的公平性,CFS 采用了负载平衡机制,Kolivas 认为,这些复杂代码抵消了 per cpu queue 曾带来的好处。
最后,主流内核的 CFS 还是对睡眠进程存在一些偏好,这意味着"不公平"。
在现实中,调度算法类似一个处境尴尬的主妇,满足孩子对晚餐的要求便有可能伤害到老人的食欲。Linux 内核一直试图做出一道让全家老少都喜欢的菜,在这方面,CFS 已经做的很好。但一道能被所有人接受的菜,或许就意味着稍许平淡。而 BFS 只打算满足一种口味,以便将这种口味发展到极限。
根据 Linux Magazine的说法,Con Kolivas是看到了下面这则来自 xkcd 的漫画而开始思考 BFS 的。
事情源于一些 Linux 用户,他们发现 Linux 虽然号称能够充分发挥 4096 颗 CPU 系统的计算能力,但在普通的 laptop 上却无法流畅地播放 Youtube 视频。
这让人们开始思考,对于 Desktop 环境来讲,CFS 哪些复杂的特性究竟是否还有意义?人们是否有必要在自己的个人电脑中使用一个支持 4096 个 CPU 的调度器?
BFS 正是对这种质疑的自然反应。它不打算支持 4096 个 CPU 的庞然大物,BFS 的目标是普通人使用的桌面电脑。此外,BFS 还删除了那些只有在服务器上才需要的特性。比如,BFS 抛弃了 CFS 的组调度特性,类似 CGROUP 这样的特性对于普通的桌面用户是多余的技术。
这很容易理解:在只有一个 CPU 的系统中,谁还会设计多个 CGroup,哪里还能用到 NUMA domain等概念呢?
此外 BFS 使用单一的 run queue,不再需要复杂的负载均衡机制。由于不再有 CGROUP 概念,也不再需要 Group 间的负载均衡。
这些简单的裁剪使得 BFS 的代码极大地简化,简化的代码意味着执行一次调度所需要的指令数减少了,相应的 footprint 自然也减少了。
当然简化代码只是一个显而易见的方面,更重要的是,这种理念的不同会对最终的调度器实现产生更加深远的影响,这实在是难以尽述。
多队列 vs 单一队列
在 Linux 内核进入 2.6 时,调度器采用 per cpu run queue 从而克服了单一 run queue 的局限。在多 CPU 系统中,单一 run queue 意味着 run queue 成为了系统的瓶颈,因为在同一时刻,一个 CPU 访问 run queue 时,其他的 CPU 即使空闲也必须等待。当使用 per CPU 的 run queue 之后,每个 CPU 不必再使用大锁,从而能够并行地处理调度。
但很多事情都不像第一眼看上去那样简单。
Kolivas 发现,采用 per cpu run queue 所带来的好处会被追求公平性的 load balance 代码所抵消。在目前的 CFS 调度器中,每颗 CPU 只维护本地 run queue 中所有进程的公平性,为了实现跨 CPU 的调度公平性,CFS 必须定时进行 load balance,将一些进程从繁忙的 CPU 的 run queue 中移到其他空闲的 run queue 中。
这个 load balance 的过程需要获得其他 run queue 的锁,这种操作降低了多运行队列带来的并行性。
并且在复杂情况下,这种因 load balance 而引入的 footprint 将非常可观。
当然,load balance 引入的加锁操作依然比全局锁的代价要低,这种代价差异随着 CPU 个数的增加而更加显著。但请您注意,BFS 并不打算为那些拥有 1024 个 CPU 的系统工作,假若系统中的 CPU 个数有限时,多 run queue 的优势便不明显了。
而 BFS 采用单一队列之后,每一个需要调度的新进程都可以在全局范围内查找最合适的 CPU,而无需 CFS 那样等待 load balance 代码来决定,这减少了多 CPU 之间裁决的延迟,最终的结果是更小的调度延迟。
向前看还是向后看?
多年来 Kolivas 一直关注着 Linux 在 desktop 上的表现。对于 desktop 的用户,最注重的不是系统的吞吐量,而是交互性程序的流畅体验。从 SD 开始,Kolivas 就告诉内核黑客们,完全公平能够从根本上保证交互性。他始终坚持一个基本观点:调度器应该 forward look only。决不要去考虑一个进程的过去。
CFS 却偏偏要考虑进程的过去。2.6.23 的时候,CFS 记录并使用 sleep time。之后不久,在 2.6.24 发布的时候,CFS 合并了"Real Fair Scheduler",删除了 sleep time。因此在 2.6.24 之后的内核中,CFS 终于也不再考虑进程过去的睡眠时间。
但 CFS 还是保留了 sleeper fairness 的思想,当进程 wakeup 的时候,在 place_entity() 函数中,CFS 将对 sleeper 进行奖励,以便其能尽快得到 CPU。这个策略是非常微妙的,我们在 2.1 节中详细介绍了 sleeper fairness 的演进过程。假如您花些时间回头再看看,就会发现 sleeper fairness 曾造成怎样严重的延迟问题。虽然 Ingo 自称 Gentle fairness 解决了延迟问题,但从代码上看,Gentle Fairness 只是对 sleeper 的奖励减半而已。因此我们可以说,CFS 依然对 Sleeper 进程进行奖励,这代表着一种偏好,一种"不公平"。而这,正是 BFS 所反对的。
BFS 中,当一个进程 wakeup 时,调度器将根据进程的 deadline 来进行选择(关于 deadline 本文将在第 4 章中详细描述),其结果是,更早睡眠的进程能更快地得到调度;CFS 的 sleeper fairness 则意味着要根据 wakeup 的时间来选择下一个被调度的进程,更早 wakeup 的进程会更快得到调度。
这种不同究竟会对桌面应用造成何种影响尚没有理论依据可以参考。但我个人认为,BFS 的策略更加合理。
您现在可能已经读得有些烦躁了 ( 这些英文加中文的说些啥啊 ),所以我还是尽快介绍一下 BFS 的实现细节吧。然后或许您会理解我,有些词还是不翻译更好。
Linux综合试题
一、填空题( 20%) 1. 默认情况下,超级用户和普通用户的登录提示符分别是: “#”和“ $”。 2. Linux 内核引导时,从文件 /etc/fstab 中读取要加载的文件系统。 3. Linux 系统下经常使用的两种桌面环境是: GNOME 和 KDE。 4. 链接分为: 硬链接 和 符号链接 。 5. Linux 系统中有三种基本的文件类型: 普通文件、目录文件和设备文件 。 6. 某文件的权限为: drw-r--r-- ,用数值形式表示该权限, 则该八进制数为: 644 ,该文件属性是 目录 。 7. 在超级用户下显示 Linux 系统中正在运行的全部进程,应使用的命令及参数是 ps -aux 。 8. 将前一个命令的标准输出作为后一个命令的标准输入,称之为 管道 。 9. /sbin 目录用来存放系统管理员使用的管理程序。 10. 观察当前系统的运行级别可用命令: who
浙工大Linux实验报告
#ifndef _PAGE_H #define _PAGE_H class cpage { public: int m_nPageNumber, m_nPageFaceNumber, m_nCounter, m_nTime; }; #endif #ifndef _PAGECONTROL_H #define _PAGECONTROL_H class CpageControl { public: int m_nPageNumber,m_nPageFaceNumber; class CPageControl * m_pNext; }; #endif #ifndef _MEMORY_H #define _MEMORY_H class CMemory { public: CMemory(); void initialize(const int nTota
Kiwi Linux是面向i386架构的一份修改过的Ubuntu自启动运行光盘,它包含罗马尼亚语和匈牙利语的本地化,多媒体编码解码器,对加密DVD的支持, 面向Firefox的Flash及Java插件,用于访问本地互联网服务(Clicknet和RDS)的PPPoE图形用户界面,以及对NTFS分区的写 支持。
生产调度是一项日常性的工作,应当把一些反映生产调度规律性的、行之有效的例行工作方法制度化,以指导调度工作的有效开展。调度工作制度一般有:值班制度、调度会议制度、现场调度制度、调度报告制度等。其内容视企业具体情况而定。
实行值班制度
为了组织调度,及时处理生产中出现的问题,厂部、车间都应建立调度值班制度。规模较大的企业可设中央调度控制台。厂部、车间都要设值班调度,处理日常生产中的问题。值班调度在值班期内,要经常检查车间、工段作业完成情况及科室配合情况,检查调度会议决议的执行情况,及时处理生产中的问题,填写调度日志,把当班发生的问题和处理情况记录下来实行调度报告制度。为了使各级调度机构和领导及时了解生产情况,企业各级调度机构要把每日值班调度的情况报告给上级调度部门和有关领导。企业一级生产调度机构要把每日生产情况、库存情况、产品配套进度情况、商品出产进度情况等,报企业领导和有关科室、车间掌握。
坚持调度会议制度
调度会议是一种发扬民主、集思广益、统一指挥生产的良好形式。企业一级调度会议由企业负责生产的领导主持,主管调度工作的科长召集,各车间主任及有关科室科长参加。车间调度会由车间主任主持,车间计划调度组长召集,车间技术副主任、工具员参加。会前要做好准备,事先摸清问题,通知会议内容,集中解决生产中的关键问题。会议上议题要突出重点,要强调协作风格。会议既要发扬民主,又要有统一意志。
健全现场调度制度。领导人员下现场,到发生问题的现场去,会同调度人员、技术人员、工人三结合地研究生产中出现的问题,以求得矛盾的解决。这种方法有利于领导人员深入实际,密切联系群众,掌握下情,调动各方面的积极性,使问题可以获得又快又好的解决。
坚持班前班后小组会制度
小组通过班前会布置任务,调度生产进度;通过班后会检查生产进度计划完成情况,总结工作。
什么是shell程序呢"_blank" href="/item/linux">linux命令的文件.
像编写高级语言的程序一样,编写一个shell程序需要一个文本编辑器.如Ⅵ等.
在文本编辑环境下,依据shell的语法规则,输入一些shell/linux命令行,形成一个完整的程序文件.
执行shell程序文件有三种方法
⑴#chmod x file(在/etc/profile中,加入export PATH=${PATH}:~/yourpath,就可以在命令行下直接运行,像执行普通命令一样)
⑵#sh file
⑶# . file
⑷#source file
在编写shell时,第一行一定要指明系统需要那种shell解释你的shell程序,如:#! /bin/bash,#! /bin/csh,/bin/tcsh,还是#! /bin/pdksh .
⑴常用系统变量
$ # :保存程序命令行参数的数目
$ "para" label-module="para">
$ 0 :保存程序名
$ * :以("$1 $2...")的形式保存所有输入的命令行参数
$ @ :以("$1""$2"...)的形式保存所有输入的命令行参数
⑵定义变量
shell语言是非类型的解释型语言,不象用C /JAVA语言编程时需要事先声明变量.给一个变量赋值,实际上就是定义了变量.
在linux支持的所有shell中,都可以用赋值符号(=)为变量赋值.
如:
abc=9 (bash/pdksh不能在等号两侧留下空格)
set abc = 9 (tcsh/csh)
由于shell程序的变量是无类型的,所以用户可以使用同一个变量时而存放字符时而存放整数.
如:
name=abc (bash/pdksh)
set name = abc (tcsh)
在变量赋值之后,只需在变量前面加一个$去引用.如:
echo $name
⑶位置变量
当运行一个支持多个命令行参数的shell程序时,这些变量的值将分别存放在位置变量里.
其中第一个参数存放在位置变量1,第二个参数存放在位置变量2,依次类推...,shell保留
这些变量,不允许用户以令外的方式定义他们.同别的变量,用$符号引用他们.
shell使用引号(单引号/双引号)和反斜线("\")用于向shell解释器屏蔽一些特殊字符.
反引号(")对shell则有特殊意义.
如:
abc="how are you" (bash/pdksh)
set abc = "how are you" (tcsh)
这个命令行把三个单词组成的字符串how are you作为一个整体赋值给变量abc.
abc1='$LOGNAME,how are you!' (bash/pdksh)
set abc1='$LOGNAME,how are you!' (tcsh)
abc2="$LOGNAME,how are you!" (bash/pdksh)
set abc2="$LOGNAME,how are you!" (tcsh)
LOGNAME变量是保存当前用户名的shell变量,假设他的当前值是:wang.执行完两条命令后,
abc1的内容是:$LOGNAME,how are you!.而abc2的内容是;wang,how are you!.
象单引号一样,反斜线也能屏蔽所有特殊字符.但是他一次只能屏蔽一个字符.而不能屏蔽
一组字符.
反引号的功能不同于以上的三种符号.他不具有屏蔽特殊字符的功能.但是可以通过他将
一个命令的运行结果传递给另外一个命令.
如:
contents=`ls` (bash/pdksh)
set contents = `ls` (tcsh)
在bash/pdksh中,命令test用于计算一个条件表达式的值.他们经常在条件语句和循环
语句中被用来判断某些条件是否满足.
test命令的语法格式:
test expression
或者
[expression]
在test命令中,可以使用很多shell的内部操作符.这些操作符介绍如下:
⑴字符串操作符 用于计算字符串表达式
test命令 | 含义
Str1 = str2 | 当str1与str2相同时,返回True
Str1! = str2| 当str1与str2不同时,返回True
Str | 当str不是空字符时,返回True
-n str | 当str的长度大于0时,返回True
-z str | 当str的长度是0时,返回True
⑵整数操作符具有和字符操作符类似的功能.只是他们的操作是针对整数
test表达式 | 含义
Int1 -eq int2|当int1等于int2时,返回True
Int1 -ge int2|当int1大于/等于int2时,返回True
Int1 -le int2|当int1小于/等于int2时,返回True
Int1 -gt int2|当int1大于int2时,返回True
Int1 -ne int2|当int1不等于int2时,返回True
⑶用于文件操作的操作符,他们能检查:文件是否存在,文件类型等
test表达式 | 含义
-d file |当file是一个目录时,返回 True
-f file |当file是一个普通文件时,返回 True
-r file |当file是一个可读文件时,返回 True
-s file |当file文件长度大于0时,返回 True
-w file |当file是一个可写文件时,返回 True
-x file |当file是一个可执行文件时,返回 True
⑷shell的逻辑操作符用于修饰/连接包含整数,字符串,文件操作符的表达式
test表达式 | 含义
! expr |当expr的值是False时,返回True
Expr1 -a expr2|当expr1,expr2值同为True时,返回True
Expr1 -o expr2|当expr1,expr2的值至少有一个为True时,返回True
注意:
tcsh shell 不使用test命令,但是tcsh中的表达式同样能承担相同的功能.tcsh
支持的表达式于C中的表达式相同.通常使用在if和while命令中.
tcsh表达式 | 含义
Int1 <= int2 |当int1小于/等于int2时,返回True
Int1 >= int2 |当int1大于/等于int2时,返回True
Int1 < int2 |当int1小于int2时,返回True
Int1 > int2 |当int1大于int2时,返回True
Str1 == str2 |当str1与str2相同时,返回True
Str1 != str2 |当str1与str2不同时,返回True
-r file |当file是一个可读文件时,返回True
-w file |当file是一个可写文件时,返回True
-x file |当file是一个可执行文件时,返回True
-e file |当file存在时,返回True
-o file |当file文件的所有者是当前用户时,返回True
-z file |当file长度为0时,返回True
-f file |当file是一个普通文件时,返回True
-d file |当file是一个目录时,返回True
Exp1 || exp2 |当exp1和exp2的值至少一个为True时,返回True
Exp1 && exp2 |当exp1和exp2的值同为True时,返回True
! exp |当exp的值为False时,返回True