什么是操作系统以及为什么学习 Linux?

本文的读者针对的是完全不懂 Linux 的初学者,着重强调“知其所以然”和“二八定理”,也就是说我不光会讲解 Linux 操作,也会讲解背后的原理;同时侧重于最高频使用的命令摘出来,给初学者提供重点。

要想理解操作系统,需要先理解 CPU。CPU 就是一个计算器,可以做数学和逻辑运算,本身是使用很底层的语言来操作的,以我扩展过的 XV6 操作系统举例,里面的 CPU 命令是这样的:

 9c2:	7139                	addi	sp,sp,-64
 9c4:	fc06                	sd	ra,56(sp)
 9c6:	f822                	sd	s0,48(sp)
 9c8:	f426                	sd	s1,40(sp)
 9ca:	f04a                	sd	s2,32(sp)
 9cc:	ec4e                	sd	s3,24(sp)
 9ce:	e852                	sd	s4,16(sp)
 9d0:	e456                	sd	s5,8(sp)
 9d2:	e05a                	sd	s6,0(sp)
 9d4:	0080                	addi	s0,sp,64

左边的是操作 CPU 的语言“机器码”,右边是汇编,汇编和机器码是一比一对应的关系,只是在这些二进制(上述命令把二进制转为了十六进制)的基础上给命令起了名字。这些细节不需要读者掌握,只需要有个大致概念。

可以感受到 CPU 是非常底层的,使用起来是很不方便的,所以就有了操作系统,它用软件封装了 CPU,直接给我们提供了非常高层的功能,让使用 CPU 变得更加容易,比如进程管理、多用户、文件系统。所以操作系统就是一个承上启下的软件,向下对接 CPU,向上给开发者写的各种软件提供调用的各种函数功能。我们日常使用的各种软件,包括浏览器、聊天工具、编程语言等等,本质上都是一个运行在操作系统上面的软件,需要调用操作系统的提供的函数来完成各种功能。

那么操作系统提供了哪些函数呢?早期的操作系统有一个叫做 POSIX 的概念,也就是说希望遵循这个规范的操作系统都可以实现相同的一套函数,涵盖操作系统的所有功能。还是以我之前拓展的 XV6 为例:

int read(int, void*, int);
int close(int);
int open(const char*, int);

这些函数都是针对文件做操作。叫做 System Call。常用的这些软件都是基于 System Call 来做开发的。

基于 System Call 开发的软件,也就是应用软件,需要暴露一个使用界面给用户,就像空调的遥控器、汽车的按钮和触摸屏一样。这时就分化出了两种方向:

  1. 图形化操作界面(GUI),可以让用户用鼠标拖拉点拽。
  2. 命令行操作界面(TUI),需要用户用程序命令去操作。

所谓的学习 Linux,主要就是学习 Linux 的命令行操作,通常所说的终端(Terminal、Shell 等等),也是同一个意思。 初学者可能无法理解为什么要使用这种”很不方便“的方式操作 Linux,其实命令行是有很大好处的:

  1. 可以批量化操作,比如一个命令就可以把某种后缀的文件全部移到另一个文件夹。
  2. 单个命令拥有很大的信息量,比如打开一个路径非常长的文件,如果用图形化操作需要点击很多次。
  3. 可以自动化,如果一个操作需要大量的命令,我们可以用一个脚本来一键执行所有命令。对于图形化操作就很难了。

不难发现,这些优点背后都指向一个特征:自动化。 因为操作系统设计出来,最初就是给程序员使用的,程序员写程序和部署程序都追求自动化,所以命令行就携带了这种思想。

这也是我们学习 Linux 命令行的原因,无论编程还是数据分析,都需要在 Linux 服务器上部署程序,所以都需要了解命令行。

Linux 历史梳理

最初比较流行的操作系统是 Unix,是由贝尔实验室的 Ken Thompson 和 Dennis Ritchie 用业余和摸鱼时间开发的,项目从 1969 年开始,值得一提的是这个操作系统是为了方便他们打游戏,而 AT&T 公司很快就放弃了这个项目,两人不管上层的意见,坚持开发,最后做出了这个风靡一时的操作系统。

而 Unix 问世不久,就被 AT&T 盯上了,他们希望通过这个操作系统收取费用,于是 Unix 就陷入了版权问题。这时有一个芬兰的大学生极客 Linus Torvalds 处于兴趣,于 1991 年编写了一个操作系统(而他的 idea 来源根源其实在 Unix,所以两个操作系统都有非常相似的哲学),因为 Unix 的版权纠纷,这个操作系统乘风而起,随之风靡全世界。

Linux 最大的标志性事件就是成为了世界上首个大规模的开放协作的开源软件系统,之前的极客届的开源软件更多是指免费(Free Sofware),也就是用户可以免费使用以及自由修改。而 Linux 开放了协作,也就是说全世界各地的人不论出生,都可以在水平足够的情况下给这个项目贡献源码。

截至目前,Linux 的项目规模有千万行,来自世界各地贡献者上万,参与的机构数量上千。在这个四分五裂的世界,无疑是一个人类通力协作的社会学奇迹。

SSH、FileZilla

要使用 Linux 需要一个入口,对于初学者常用的入口有两个软件:SSH 和 Filezilla。

其中 SSH 用来远程登录服务器,一般我们很少在 Linux 服务器上直接操作,都是用自己的电脑登录然后间接操作。

只要输入这个命令

ssh ubuntu@49.232.xx.xx

输入密码之后,就可以登录进入服务器。需要注意的是 SSH 和 Filezilla 也都是基于操作系统 System Call 开发的软件。

其中 ssh 是命令,后面跟着的 ubuntu 是用户名,@ 后面是服务器的 IP 地址。用这个命令进入 Linux 之后就可以通过命令操作服务器了。

而 Filezilla 是基于对于服务器的远程登录实现的文件上传于下载软件,毕竟除了运行程序,很多情况下都需要和服务器有文件交互,这个软件是基于 GUI 的,可以参考这篇教程.

用户系统

接下来的内容都以我自己的服务器为例:

多用户功能是 Linux 最基本的功能之一,它允许多个用户登录操作系统,而且每个用户的文件是互相隔离的,同时有一套详细的权限系统。

这里也是很多初学者容易困惑的地方,这里争取一次性讲透。

我们在服务器上运行这个命令:

ls -al    

其中 ls 是指列出文件夹,后面跟着的参数可以列出详细的属性。

如果不知道某个命令是什么意思,除了搜索之外,还可以使用 Linux 自带的手册 man:

man ls

然后可以看到手册界面,里面有关于这个命令详细的描述,按 q 就可以退出:

LS(1)                                                         User Commands                                                         LS(1)

NAME
       ls - list directory contents

SYNOPSIS
       ls [OPTION]... [FILE]...

DESCRIPTION
       List  information about the FILEs (the current directory by default).  Sort entries alphabetically if none of -cftuvSUX nor --sort
       is specified.

       Mandatory arguments to long options are mandatory for short options too.

       -a, --all
              do not ignore entries starting with .

       -A, --almost-all
              do not list implied . and ..

       --author
              with -l, print the author of each file

       -b, --escape
              print C-style escapes for nongraphic characters

       --block-size=SIZE
              with -l, scale sizes by SIZE when printing them; e.g., '--block-size=M'; see SIZE format below

       -B, --ignore-backups
              do not list implied entries ending with ~

       -c     with -lt: sort by, and show, ctime (time of last modification of file status information); with -l: show ctime and sort  by
              name; otherwise: sort by ctime, newest first

ls 命令的结果如下:

total 20
drwxr-xr-x  5 root                  root                  4096 Sep 19 11:35 .
drwxr-xr-x 20 root                  root                  4096 Jan  4 11:06 ..
drwxr-x---  7 jupyter-jupyter-admin jupyter-jupyter-admin 4096 Oct 18 11:48 jupyter-jupyter-admin
drwxr-xr-x  5 rserver               rserver               4096 Sep 15 10:34 rserver
drwx------ 10 ubuntu                ubuntu                4096 Jan  4 11:07 ubuntu

其中最右边是指文件和文件夹的名字,中间两行分别是指用户和用户组,用户组指的是一组用户,这里不用关心。

最重要的部分是最开头的神秘字符串,它看似复杂,其实背后的原理很简单,就是试图用十个字符描述两个信息:

  • 第一个字母 d 指这一行是文件夹,如果是一个 ”-“ 就是指文件。
  • 接下来的九个字母,都是 rwx 的重复,rwx 分别指读、写、执行的权限,如果是 - 则表明没有这个权限。

那么为什么是三个重复呢?因为权限涉及三组用户:文件所有者、所有者所在的用户组、其他人。 就以 ubuntu 这个文件夹来说,”drwx——“ 表明文件所有者可以读、写、执行这个文件夹的内容,但是用户组和其他人是不可以的,什么都做不了。

知道怎么查看文件权限,接下来就需要了解怎么修改权限。这个命令如下:

chmod -R o=rwx ubuntu

第二个参数是指将这个文件夹里面的所有文件全部修改权限,第三个参数指想要修改成什么权限,第四个参数是文件名字。 如果只想要修改一个文件,可以把 -R 去掉。 其中 ”o=rwx“ 中,o 指的是其他用户,u 和 g 分别是所有者和用户组,而 rwx 就是想要修改成的权限。 当运行完这个命令后,ubuntu 这个文件夹前后的权限分别为:

之前
drwx------ 10 ubuntu                ubuntu                4096 Jan  4 11:27 ubuntu
之后
drwx---rwx 10 ubuntu                ubuntu                4096 Jan  4 11:28 ubuntu

需要注意的是这个操作需要时管理员或者文件夹的所有者来执行。

文件系统

学习文件系统,需要理解

  • 权限
  • 相对路径和绝对路径
  • 如何浏览目录和查看文件

其中权限已经讲过了,主要剩下的两个部分。 文件的路径有两种,分别称之为绝对路径和相对路径。 首先需要理解当前的工作目录:

pwd

结果为:

/home/rserver/R/x86_64-pc-linux-gnu-library

可以看到里面嵌套了多层,从最根部的 /home 目录开始,一直到 x86_64-pc-linux-gnu-library。这个命令是打印出来我们当前所在的文件夹位置,我们当前就处于 x86_64-pc-linux-gnu-library 这个文件夹里面,它就是我们的工作目录(当前所处文件夹)。 看一下这个文件夹里面的内容:

ls

结果为:

4.2

可以看到里面有一个叫做 4.2 的文件夹。 然后当我们想要进入这个文件夹时,就有两种选择:

  • 基于当前的工作目录,直接进入,这种情况下直接输入当前的文件夹名字,不需要加上之前的路径:
cd 4.2

其中 cd 的意思是进入一个文件夹。

  • 从根目录开始直接进入一个目录,不考虑当前的工作目录:
cd /home/rserver/R/x86_64-pc-linux-gnu-library/4.2

前者就是相对路径,后者就是绝对路径。 那么如何进入当前目录的上一层目录呢?可以使用 .. 作为 上一层文件夹的名字,比如在 4.2 中,运行

cd ..

就进入了 x86_64-pc-linux-gnu-library 中。这个命令还是可以叠加的:

cd ../..

这样就回到了上上层目录。

下载软件

下载软件需要理解两个概念:环境变量和路径变量。

环境变量指的是 Linux 在运行过程中储存的一些变量值,可以供一些程序使用;其中最常用到的就是路径变量。比如当我们在命令行输入 python 的时候,操作系统是从哪里找到这个软件呢?它不可能做全局搜索,这样太慢了,它会从一些默认的文件夹进行搜索,这些文件夹就存在路径变量里面:

echo $PATH

这个命令就可以打印路径变量:

/root/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

其中每个 : 都是一个文件夹的分隔符,然后可以看到里面有大量的文件夹。 我们看下 python 在哪里:

which python

结果为:

/usr/bin/python

也就是说 python 可执行文件安装到了 /usr/bin 这个文件夹下面。

接下来看下载软件。Linux 中下载软件有两种,一种是从官网手动下载,另一种是从包管理软件下载。前者相对更加琐碎,后者相当于苹果手机的 App Store。

以做基因分析常用的 plink 为例。

官网下载:

我们从 官网 下载 Linux 64 位的软件,然后把它上传到服务器(或者用 wget 直接下载),然后可以看到里面有大量的文件,找到其中的 plink 文件。这时需要用到两个知识点,一是权限,二是路径变量。 首先更改它的权限,让它成为可执行文件:

chmod +x plink

然后移动到路径变量的文件夹里面:

mv plink /usr/bin

接下来我们在全局的任何一个地方都可以使用 plink 了。

包管理软件下载:

Ubuntu 是 Linux 的一种发行版,它常用的包管理软件是 apt。用 apt 下载的命令:

apt-get install plink2

注意这里是 plink2,因为 plink 分为两个版本 1 和 2,2 相对更新一些。

我们可以用命令看下它安装在了哪里:

which plink2
结果是:
/usr/bin/plink2

查看内存

查看内存分为 RAM 和磁盘内存,用来做操作系统的负载监控。 第一个命令是 free,用来看使用的 RAM:

free -m

结果为:
              total        used        free      shared  buff/cache   available
Mem:            976         556         112          15         308         250
Swap:             0           0           0

-m 指的是使用 MB 作为单位,可以看到我的服务器有将近 1G,里面使用了 556 MB,剩下的基本都是可用的。

第二个可以看到 RAM 更加详细的信息,用来排查看哪个进程占用比较多:

top

结果为:

top - 15:45:44 up 190 days, 18:06,  1 user,  load average: 0.03, 0.05, 0.05
Tasks: 121 total,   1 running, 120 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.0 us,  1.0 sy,  0.0 ni, 97.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :    976.4 total,    119.4 free,    548.2 used,    308.8 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.    258.5 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                               
2209460 root      20   0  989992  56312  18744 S   0.7   5.6 128:32.92 YDService                                                             
2333650 root      20   0  558216  15184   3568 S   0.7   1.5 289:22.15 barad_agent                                                           
    923 root      20   0 1305120   7244   5136 S   0.3   0.7  49:12.90 YDLive                                                                
1096301 root      20   0  164928  54308   4332 S   0.3   5.4 601:46.17 gunicorn                                                              
1096303 root      20   0  163952  52428   2760 S   0.3   5.2 601:48.37 gunicorn                                                              
2219546 jupyter+  20   0  221956  93748   3556 S   0.3   9.4 335:37.05 jupyterhub-sing                                                       
2333075 root      20   0  160484  50180   4508 S   0.3   5.0 251:26.65 gunicorn                                                              
      1 root      20   0  179228  10660   6032 S   0.0   1.1   6:47.76 systemd                                                               
      2 root      20   0       0      0      0 S   0.0   0.0   0:05.99 kthreadd                                                              
      3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp                                                                
      4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp                                                            
      6 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/0:0H-kblockd                                                  
      9 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 mm_percpu_wq                                                          
     10 root      20   0       0      0      0 S   0.0   0.0  11:05.85 ksoftirqd/0                                                           
     11 root      20   0       0      0      0 I   0.0   0.0  23:43.17 rcu_sched                                                             
     12 root      rt   0       0      0      0 S   0.0   0.0   0:44.96 migration/0                                                           
     13 root     -51   0       0      0      0 S   0.0   0.0   0:00.00 idle_inject/0                                                         

可以看到里面运行的程序,最后是程序的命令,还可以看到每个程序占用的 CPU 和 内存的比重。

第三个就是 du,查看磁盘使用率的:

du -h --max-depth=1

结果是:

1.6M    ./rserver
1.3G    ./ubuntu
180K    ./jupyter-jupyter-admin
1.3G    .

-h 查看具体信息,–max-depth=1 可以只查看往下一层的文件夹,否则就会一直遍历到最底端。

编辑文件

编辑文件可以考虑使用 Vim 和 Visual Studio Code 远程模式。前者优点是可以直接在操作系统上编辑,缺点是作为 TUI 软件需要学习它特殊的命令,后者优点是在本机使用 GUI 的编辑软件去编辑文件,缺点是需要做一些配置。我一般会用后者在服务器上做程序编写,如果临时改一些简单的文件就直接登录服务器使用 Vim。

这一块展开内容太多,这里只是做一个索引,就不赘述了。详情可以参考资料部分。

总结

这里我们学习过的命令有:ssh、ls、man、chmod、pwd、cd、echo、which、mv、free、top、du。

资料

后续想要更加深入学习 Linux 操作,可以阅读以下资料:

Visual Studio Code 官方教程,方便远程编辑文件

MIT 的操作系统常用软件教程