操作系统 Pro

计算机是由以下几个单元组成的:包括输入单元、输出单元、CPU内部的控制单元、算数逻辑单元与主存储器五大部分。

CPU种类主要有两种:RISC-精简指令集 和 CISC-复杂指令集。

RISC的设计重点在于降低由硬件执行指令的复杂度,因为软件比硬件容易提供更大的灵活性和更高的智能,因此RISC设计对编译器有更高的要求;而CISC的设计则更侧重于硬件执行指令的功能,使CISC的指令变得很复杂。总之RISC的指令集精简,执行效率好,但对编译器的要求高,而CISC强调硬件的复杂性,指令集多而复杂,执行效率差,但每条指令的功能丰富。

CPU频率=外频*频,我们常说的超频指的是设定主板的外频或者是倍频为较高频率的一种方式。

一般主板芯片组有北桥和南桥。北桥称为系统总线,连接CPU、内存和显卡等快速设备,南桥称为输入输出总线,连接硬盘、USBPCI接口和网卡等慢速设备。

北桥所支持的频率称为前端总线速度,而每次传送的位数则是总线宽度。常见的总线宽度有3264位(bits),另外所谓的总线带宽则是 前端总线速度*总线宽度,即每秒可传送的最大数据量。

CPU每次能够处理的数据量称为字组大小,也有32位和64位之分,而32CPU只能支持最大4GBytes的内存。

内存通常有SDRAMDDR SDRAM两种,但DDR拥有更快的传输频率,所以SDRAM已经逐渐被淘汰啦。

CPU内部还存在高速缓存,以提高CPU的效率,这里就要用到静态随机存储内存,即SRAM,通常容量很小,但速度很快。

CMOS芯片是主板上一块可读写的RAM芯片,用于保存BIOS设置的各项硬件配置信息和用户设定的某些参数,由主板上的纽扣电池供电,即使系统断电信息也不会丢失。而BIOS则是主板上的一块EPROMEEPROM芯片,用于存放系统重要信息和BIOS设置程序。

显卡内拥有显存,这是因为每个图像的颜色会占用掉内存,而有的显卡甚至拥有GPU,用于3D加速,这对于游戏是非常重要的性能。

注意硬盘的结构,拥有扇区(Sector)、磁道(Cylinder)和Header头这几个概念,所以硬盘的总容量计算公式为 Header数量*每个Header负责的磁道数*每个磁道所含有的扇区数量*每个扇区的字节数。另外我们通常500GB的硬盘指的是十进制的500\*1000\*1000\*1000Bytes的大小,所以实际上仅拥有460GBytes左右的容量。

计算机中每个设备都有一个I/O地址和IRQ中断。两个设备不能使用同一个I/O地址,而IRQ中断是设备联系CPU的专门路径,每个设备可以通过IRQ中断告知CPU自己的工作情况,以方便CPU分配任务。

计算机依次由 硬件–核心(kernel)–系统呼叫层(system call)–应用程序 这几个部分组成。其中 kernel+系统呼叫层+常用的应用程序 组成了现在的操作系统。而Linux kernel包含了对硬件进行管理的核心以及向应用程序提供系统调用的接口。

Linux kernel分奇数和偶数两种版本,其中偶数版代表稳定版,奇数版代表测试版或不稳定版本。

硬盘里第一块扇区最重要,一般只有512bytes,里面存放着主引导记录(MBR)和磁盘分区表(Partition Table)。MBR主要用来引导启动系统,分区表只能保存四个主分区或逻辑分区,而逻辑分区只能有一个,至于逻辑分区表则保存在逻辑分区的第一个扇区里,因此可以给逻辑分区划分更多的子逻辑分区。

一般开机的流程是:BIOSMBRBoot LoaderGrubNT5/NT6等)–Kernel

Boot Loader可以存在的地方有两个:MBRBoot Sector

LinuxCtrl+D代表End Of FileEOF的意思,这个快捷键可以取代exit的功能,直接跳出文字界面。

Linux命令行下按Tab键可以补齐命令,maninfo命令可以查看command的帮助文档,Ctrl+C表示中断进程,Ctrl+D表示EOF特殊字符,Ctrl+Z表示挂起进程在后台运行。

Linux系统下,用户和root相关信息记录在/etc/passwd下,个人密码则是记录在/etc/shadow下,所有的组名都记录在/etc/group内。

Linux的权限不是很细致,拥有rwx三种:

`r`(`Read`,读取):   对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目录的权限。

`w`(`Write`,写入):  对文件而言,具有新增,修改,删除文件内容的权限;对目录来说,具有新建,删除,修改,移动目录内文件的权限。

`x`(`Execute`,执行):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。

可以用chgrp改变文件的用户组,chown改变文件的所有者,chmod改变文件的权限。

Linux下文件的可删除和重命名权限是由其所在目录的write权限所决定的,要了解目录权限的意义。

Linux下的文件类型:-代表常规文件,d代表目录,l代表链接,bblock)和cchar)代表设备文件,s代表socket文件,p代表pipe管道文件。

pwd会显示出当前目录的路径,注意 -P 选项,如果当前目录只是以链接文件的形式存在,那么 pwd -P 就会显示出链接真正所指向的路径。

cp命令:cp -a souce dest 相当于 cp -pdr source dest,完全复制目录的属性和档案,甚至是链接文件。如果不加任何参数的 cp 一个软链接,复制的结果会是源文件,而不是软链接,用 -d 可以解决,注意。

删除带有-开头的档案,例如 -aaa 这个文件,必须 rm ./-aaarm -- -aaa 才可以删除,否则-aaa会误判为参数。

查看二进制文件,有 odxxd 命令,甚至有 hexdump 命令,都是以 16进制或8进制 显示输出,非常方便调试。

新建目录和档案的默认权限是由 umask 来控制的,一般我们在linux系统的 umask 设置为 022 比较好。

linux下档案的隐藏属性:chattr 命令可以设置档案的隐藏属性,常用的有i属性(任何用户包括root都无法修改),a属性(只能增加数据,不能删除数据)等;lsattr 命令可以查看档案的隐藏属性,注意属性和权限是不同的,留个记性。

linux文件的特殊权限:SUID(u+s)SGID(g+s)SBIT(o+t)。这三个特殊权限都是用来取代x权限的,所以设置这三个权限的前提条件就是必须具有x权限,否则小写的 st 权限就会变为大写的 ST 权限,表示文件还不具备x权限,更谈不上这三个权限啦。

SUID(u+s)仅能用在可执行的二进制程序上,目录无效。

拥有`SUID`权限的二进制程序在执行时,执行者会暂时取得拥有者的权限,例如 `passwd` 命令就具有`SUID`权限,使得普通用户在执行 `passwd` 命令时会暂时 `root` 用户的权限,从而能修改`/etc/passwd`文件。

SGID(u+s)不仅能用在可执行的二进制程序上,目录同样有效。

拥有`SGID`权限的二进制程序在执行时,执行者会暂时取得该程序所属的群组支持,从而能访问自己群组本不能访问的文件;

拥有`SGID`权限的目录,一旦进入该目录,那么在目录下新建任何文件和目录,它们的群组都会与该目录相同,对于项目开发还是相当有用的。

SBIT(o+t)仅能用在有x权限的目录上,文件档无效。

拥有`SBIT`权限的目录,一旦进入该目录,当用户在该目录下新建档案和目录时,仅有自己和`root`才能删除该档案,即使文件具有`g+w`,`o+w`这样的属性,也会失效。例如`/tmp`就是这样一个文件夹。

SUID权限为4SGID权限为2SBIT权限为1,因此可以用 chmod 4755 file 这样的命令来设置文件的特殊权限,还可以用 u+sg+so+t 这样的设置法。

EXT2文件系统的组成:最前面是一个Boot Sector,然后是N多个Block Group

每个Block Group主要由inodetable/datablock/superblock等部分组成:

  • superblock记录Filesystem的信息和inodeblock的大小和数量等,一般在第一个Block Group里,后面的Block Group大部分都没有,有的话也只是第一个Block Group的备份;
  • filesystem description主要记录block group的起始与结束的block号码,以及group每个区段分别介于哪一个block号码之间;
  • block bitmap记录每个block号码是否使用中;
  • inode bitmap记录每个inode号码是否使用中;
  • inode table则是记录每个 inode(文件) 的权限、属性、容量等以及它真正内容所在的block号码;
  • data block则是纯粹的数据记录。

Block Group的基本单位是blockblock size一般是1K2K4K

每个文件只有一个inode,而每个inode可能指向多个数据相同的文件,每个inode大小一般128字节或256字节。

详细的ext2文件系统信息可以用 tune2fs -l /dev/sda1dumpe2fs /dev/sda1 命令查看。

目录的链接数 包括目录本身、当前目录.和父目录..,每建立一个文件夹就多一个父目录..;文件的链接数指的是 该文件inode号的链接数,即是硬链接个数。

hdparm命令可以用来测试硬盘读取速度,不过不是很准,hdparm -Tt /dev/sda

在使用fdisk重新分区后,不要忘记使用partprobe命令让kernel更新分区表,很重要,否则系统可能会出错。

dd if=/dev/sda of=/dev/sdb,这个命令可以让两个硬盘完全相同,因为dd可以读取硬盘的所有数据,包括MBRboot sector等。

linux启动时首先挂载临时根文件系统initrdInitial Ram Disk),完成引导并挂载真正的根文件系统后再退出,不过在很多嵌入式设备中,它却是最终的根文件系统,因为它是文件系统的最小集合,非常适合嵌入式系统。

cpio指令可以备份任何档案,包括/dev下的设备档案,正因如此,现在的initrd都是采用cpio备份再用gzip压缩生成的。

dos2unix可以将windows文件的行尾字符\r\n转换成unix格式\n

iconv可以转换文件的字符编码,例如:iconv -f gbk -t utf8 test.gbk -o test.utf8

ulimit可以控制用户使用的系统资源,防止资源占用过高,系统崩溃。

envshell外置命令,可以显示当前shell的环境变量,又叫全局变量。exportshell内置命令,也可显示当前shell的环境变量。不过两者都另外有各自不同的功能,用法自己查吧。

setshell内置命令,可以显示包括环境变量、本地变量、内置变量、函数等所有shell设定值。不过它主要的功能是控制shell的内置设定,如set -o命令。

declare也是shell内置命令,一样可以显示包括变量和函数等所有shell设定值。不过它主要的功能是声明变量和数组等值类型,shell内的变量包括字符串,整数,数组,只读,导出等不同的类型和属性,记得善加利用,会事半功倍哟。

bash里面的各种变量操作,这可以节省我们的程序行数:

  • ${str#pattern}:从变量头部开始寻找符合pattern的数据,将符合的最短数据删除
  • ${str##pattern}:从变量头部开始寻找符合pattern的数据,将符合的最长数据删除
  • ${str%pattern}:从变量尾部开始寻找符合pattern的数据,将符合的最短数据删除
  • ${str%%pattern}:从变量尾部开始寻找符合pattern的数据,将符合的最长数据删除
  • ${str/old/new}:寻找变量内符合old的字符串,第一个符合的数据将被替换为new
  • ${str//old/new}:寻找变量内符合old的字符串,并将所有符合的数据替换为new

下面是变量赋值的各种替代操作,对于变量初始化很有用:

  • var=${str-expr}:如果str没有设定,var=expr
  • var=${str:-expr}:如果str没有设定或为空,var=expr
  • var=${str+expr}:如果str有设定,var=expr
  • var=${str:+expr}:如果str有设定且不为空,var=expr
  • var=${str=expr}:如果str没有设定,str=expr,var=expr
  • var=${str:=expr}:如果str没有设定或为空,str=expr,var=expr
  • var=${str?expr}:如果str没有设定,expr输出至stderr
  • var=${str:?expr}:如果str没有设定或为空,expr输出至stderr

history可以查看最近下达的指令,而!则可以执行历史命令,如!number可以下达第number号指令,!command可以下达最近以command开头的指令,这就很有效率啦。

stty可以控制终端的各种设定,如串口速率,快捷键等;此外还有set命令可以控制bash的各种功能设定;两者合作决定了我们的终端机。

bash默认组合按键:

  • Ctrl+C:终止当前命令
  • Ctrl+D:输入结束符(EOF
  • Ctrl+M:输入回车符(Enter
  • Ctrl+S:暂停屏幕输出
  • Ctrl+Q:恢复屏幕输出
  • Ctrl+U:删除提示符整行命令
  • Ctrl+Z:暂停目前的进程

bash中的标准输入,标准输出,标准错误:

  • 1>>:标准输出,覆盖形式
  • 1>>>>:标准输出,追加形式
  • 2>:标准错误输出,覆盖形式
  • 2>>:标准错误输出,追加形式
  • <:标准输入
  • <<:标准输入的结束符(EOF

对于追加的理解,我认为是输入或输出取代EOF的操作。

tee命令可以在标准输出的同时,转存一份到文件内,这对于数据分析及存储非常有用。

tr命令常用来删除特殊字符,或者对特殊字符进行转换,例如TAB符,DOS行尾符等都可以很轻松的转换和删除。

join可以连接相关数据,要求是某字段必须相同,与sort一起使用可以用来连接数据生成表格哟;paste则相对简单,不需要数据相关,直接将两行贴在一起,并用TAB隔开,也很有用。

spilt用来分割文件,可以指定文件以大小或行数来分割成N个小文件。

由于许多命令并不支持管道符,这里我们就可以使用xargs来调用不支持管道符的命令,它可以读取前面命令的输出作为参数提供给后面的命令来执行,这样就可以连接起不支持管道符的命令,用法很多。

printf命令类似于C语言的printf函数,可以格式化输出,善加运用,打印字符串会很美观。

sed的最小处理单位是行,对文本的行操作很有效率;而awk的最小处理单位是字段,对文本的列操作很有用,其命令格式如下:

awk 'pattern1{action1} pattern2{action2}...' file

常用选项:

  • awk的默认分割符是空格,可用内置变量FS指定;
  • 内置变量NF:代表每一行($0)的字段总数;
  • 内置变量NR:代表awk目前正在处理的行数;
  • pattern可以为空,常用的选项有BEGINEND,条件判断和正则表达式等;
  • 例如:awk 'BEGIN{FS=":"} $3<10{print NR"\t"$1"\t"$3} END{print FS, NF, NR}' /etc/passwd

diffpatch常用于补丁的发布:生成补丁diff -Naur dir1 dir2 > dir.patch,更新补丁patch -p0 < dir.patch,还原补丁patch -R -p0 < dir.patch

bash中的[[ ]][ ]更加高级,判断条件更加厉害,它可以判断出linux通配符(==)和正则表达式(=~),还有&&||!等高级功能,善加运用,很厉害,具体参考help [[

bash的命令行参数默认用$1 $2 ... $9来表示,超过10个参数的话必须用到shift命令,shift n可以拿掉最前面的参数,使参数偏移n位,再次查看参数个数$#时就会发现参数少了,就可以继续使用后面的参数啦。

关于shell脚本的debug,我们可以使用bash -x test.sh来进行脚本的错误检查。

Linux用于帐号管理的ACL需要文件系统的支持,并且mount选项里要有acl才行。然后就可以使用setfaclgetfacl来对文件和目录针对某一使用者的权限进行管理。

使用su - user来切换身份会更好,因为它是login-shell方式,会转化成新的用户环境,否则的话,虽然切换了身份,但环境变量还是当前用户的环境变量。

visudo可以管理用户的sudo权限,不要直接修改/etc/sudoers文件,因为会有语法问题。另外Linux下的许多需要认证的命令(例如passwd sudo su等)都会用到PAM模块,这是一个专门用于认证授权的库,可以在/etc/pam.d/*中找到支持的命令或服务。

who查看当前登入用户,write可以发送信息给用户,mesg让用户可以控制是否接受信息,wall则对所有用户进行广播信息。

手动建立用户帐号流程:

  • 建立群组(vi /etc/group
  • 同步/etc/group/etc/gpasswdgrpconv
  • 建立帐号(vi /etc/passwd
  • 同步/etc/passwd/etc/shadowpwconv
  • 建立帐号密码(passwd user
  • 建立主目录(cp -a /etc/skel /home/user
  • 更改主目录属性(chown -R user:group /home/user

针对服务器的磁盘限额配置,我们可以使用quota来配置,它也需要文件系统的支持,记得mount选项加上usrquotagrpquota

LVM可以弹性调整文件系统的容量,并且拥有快照功能,作为虚拟机的文件系统很是有用。

在特定时间进行排程工作,我们可以使用at指令,而batch可以让at任务在CPU负载较小时才进行任务。

普通用户可以使用crontab -e来设定循环工作排程,而ROOT用户则可以直接编辑/etc/crontab来设置系统的循环排程。anacron可以在系统启动时唤醒停机期间未进行的crontab任务。

ps可以截取当前系统的运行进程,pstree可以显示进程树,top可以实时监控运行进程,vmstat可以查看系统资源的使用情况。

熟悉几个kill信号的意义:1 - SIGHUP代表让程序重新读取配置文件;9 - SIGKILL代表强制中断一个程序;15 - SIGTERM代表以正常的结束方式来终止该程序。

nicerenice可以调整程序的优先级高低,PRI值越低,程序就较优先被处理。

netstatss这两个命令分属不同的网络工具包,均可以查看当前系统的网络连接状况,不过ssnetstat快多了。

fuser -uv /dev/pts/0可以根据打开的filessockets(这里是/dev/pts/0)找到运行的程序,而lsof可以列出被运行程序打开的所有文件,pidof可以找出运行程序的PID值。

Linux内核自带有SELinux安全机制,不过Ubuntu默认没有安装,一般为了安全,服务器端会启动,其主要作用是保证主体程序(主要是网络服务)仅能存取指定文件档案资源,即使程序被攻破,也不至于让黑客获得更多的文件档案和用户权限。

Linux服务程序可以分为两类:Stand Alone方式和Super Daemon方式。

  • Stand Alone方式自己单独启动并常驻内存,例如httpdvsftpd等;
  • Super Daemon方式则是所有服务由xinetd统一管理,平时不启动,需要时才由xinetd调用启动,所以比较省内存,但反应比较慢;
  • /etc/services里有所有服务的端口设置,/etc/xinetd.d则存放所有服务的配置文件,而Super Daemon的默认配置文件在/etc/xinetd.conf里。

rsync是用来同步两台电脑文件夹的程序,对于服务器备份非常有用。

/etc/hosts.allow/etc/hosts.deny只对支持TCP Wrappers的程序才有用,可以用ldd来查看程序是否支持TCP WrappersCentOS中的chkconfig可以进行系统启动服务的管理,而在Ubuntu中可以用initctlUpstart服务在/etc/init)和update-rc.dSYSV服务在/etc/init.d)来代替。

Linux系统的log主要记录在/var/log下面,不过不同的发行版记录log的文件差异颇大,可以自行配置类似/etc/rsyslog.conf的文件,设定不同log的记录位置,甚至可以开启日志服务器。最后还要配置/etc/logrotate.d/*档案来设置log的备份周期,大小,个数,动作等参数,这样就可以周期备份和替换log文件,避免让log文件太大,影响系统效率。

Linux早期通过mknod手动创建静态设备,不管设备是否被用到,这就需要在/dev下创建大量设备,但随着大量设备的出现,设备的动态检测和识别出现了问题,往往一个设备拔下再插入后设备名出现了变化,大量相同设备插入后识别困难,这对于开发者十分不便。自从内核2.6版本以后,出现了一种叫sysfs的新虚拟文件系统,它可以将内核支持的设备映射到/sys文件夹下,udev就是借此实现了用户空间(user space)的动态设备检测,创建和更新,这样系统启动时就可以动态创建设备,你还可以指定设备为特定名称,udevd后台服务将会为你自动更新设备。

Linux系统开机流程:

  • 按下Power Button,硬件逻辑电路完成CPU Reset,进入实地址模式,而其中CS:IP=FFFF0H,决定了CPU的第一条指令地址,就是跳转到BIOS首地址,于是BIOS就此启动;
  • BIOS加载CMOS的硬件信息并进行开机自检;
  • BIOS取得第一个开机装置,并读取执行MBR内的Boot Loader
  • Boot Loader依据设定加载KernelKernel挂载根目录,检测硬件并加载驱动程序;
  • 硬件驱动成功后,Kernel主动呼叫init程序,而init会取得RUNLEVEL
  • init执行sysinit完成系统环境初始化(如网络,时区等);
  • init依据RUNLEVEL启动各个服务(/etc/init.d/rc $RUNLEVEL);
  • init执行本地服务(rc.local);
  • init执行getty启动login程序,等待用户登录;

sysctl可以在系统运行时读取和修改kernel的参数,你可以在/etc/sysctl.conf里做永久修改。

Ubuntutelinit N可以用来切换当前系统的RUNLEVEL,所以你可以用telinit 0来关机,telinit 6来重启。

Linux内核模块常用命令:

  • depmod会主动分析目前内核模块的相互依赖性,并重新生成/lib/modules/$(uname -r)/modules.dep,这个文件对于modprobe命令非常重要;
  • lsmod可以列出目前内核加载的模块,modinfo可以查看某个内核模块的详细信息;
  • modprobe可以根据modules.dep文件分析依赖性,然后安装和卸载内核模块,推荐使用;
  • insmodrmmod分别是安装和卸载模块命令,不过需要完整路径,也不会分析依赖性,适合完整无依赖,自己单独编写的模块,否则不推荐使用;

我们可以利用Grub救援Linux系统,进入Grub菜单,按e进入编辑模式,在kernel后加上singleemergencyinit=/bin/bash等参数进入救援模式。

chroot可以帮助我们切换根目录,改变运行环境,如果一个Linux硬盘出了问题,可以插到另一台Linux主机上,利用chroot命令切换到问题硬盘的Linux环境上来解决问题,好像一个便携式系统哟。

nc是网络黑客利器,用处非常大,例如nc -zv 127.0.0.1 631可以扫描目标主机的631端口,还有好多好多功能,自己去看man nc吧。

Linux预设的打印服务是CUPS,可以使用http://localhost:631来连接管理打印机,也可以使用lp系列指令来管理,不详述了,如果将CUPS设定为网络打印机服务器,其他人可以使用类似ipp://192.168.1.10:631/printers/HP_PrinterURL来连接。

Ubuntu的软件管理命令:dpkg管理本地deb安装包;apt管理在线仓库的deb安装包;add-apt-repository可以增加或删除在线仓库。

对于xft字体,系统添加新字体后即可使用,fc-list查看可用字体,如果新字体没有显示,执行fc-cache -v更新字体缓存即可。

X Server管理系统硬件,X Client则是应用程序,每个X Client都不知道对方的存在,必须通过X Window Manager来管理所有的X ClientUbuntu使用lightdm来管理桌面窗口。

X Server可以启动多个,使用xinit命令并指定-display选项即可,显示位置为:0, :1 ...;命令行模式下可以使用startx来启动桌面,不过并不会加载个人设置,使用有限制,推荐使用sudo service lightdm restart来启动桌面。

Linux Kernel编译和管理命令:

  • make mrproper彻底清除目标文件和配置文件;
  • make clean清除编译过程产生的目标文件等,不会删除配置文件;
  • make menuconfig生成内核配置文件;
  • make oldconfig使用已经存在的.config作为默认值,只列出新功能选项,简化挑选过程;
  • make vmlinux编译生成未压缩的内核;
  • make modules仅编译内核模块;
  • make bzImage编译生成压缩过的内核;
  • make all等于make vmlinux modules bzImage(预设,同make);
  • make modules_install安装内核模块到/lib/modules
  • make install安装内核bzImage/boot,生成initrd.img,并更新grub配置;

Ubuntu生成initrd.img的命令是mkinitramfs,查看initrd.img内容的命令是lsinitramfs,还可以用update-initramfs管理/boot下的initrd.img文件。