Linux 新手入门教程
1991年10月5日,Linus Torvalds 在互联网上发布消息,宣布他自己开发的内核系统诞生了。他将内核源代码保存在芬兰最大的 FTP 网站上,命名为 Linux,取义
Linus's Minix
,并向全世界所有人公布。这也使得10月5日成为一个特殊的日子,以致之后的许多 Linux 版本都选择在这个日子发布。当然,如今的 Linux 一词被递归定义为Linux is not Unix
。
简介
Linux 是一套免费使用和自由传播的类 Unix 操作系统,严格来说,Linux 一词仅指其操作系统内核,不包括任何附加软件。但如今 Linux 拥有数不胜数的发行版本,广义上它们都可以叫做 Linux,典型代表如 Debian 系列、RedHat 系列、Arch 系列和 SUSE 系列等,它们也都有着各自的侧重和坚持。
桌面环境
尽管我们使用 Windows 或 OS X 操作系统的时候可能不会很在意桌面环境
,但在 Linux 下我们将需要考虑选择一个中意的桌面环境——也许是多个——或者在某些情况下,完全不必安装桌面环境,这是非常灵活且自由的。桌面环境可能是由大量组件构成的完整套件,也可能仅仅只是一个简单的窗口管理器,但无论如何,它们的核心目标都是为用户提供一个直观易用的可视化环境和视觉工作区。著名的大型桌面环境 Gnome 和 KDE 提供了杰出的图形表现和丰富的功能组件,轻量桌面环境如 Xfce、mate 和 lxde 等也算是“麻雀虽小,五脏俱全”,更有其他一些专注简洁、美观或是高效的桌面环境可选,因此我们说 Linux 的桌面环境的选择是“灵活且自由”的。
Linux 系统内核并不包括图形服务。想要使用图形环境,必须先安装 X11
,即 X Window 系统,它是最早应用于传统 Unix 系统的图形用户接口,工作于内核与桌面环境之间。这使得 Linux 拥有丰富的桌面环境以供选取。尽管桌面环境可能有风格迥异的设计,但大体上都应包括登录管理器、窗口管理器、应用启动器等组件,可能还包括一套开箱即用的软件套件,如编辑器、浏览器和终端模拟器等。大部分情况下,在使用桌面发行版的安装镜像正确安装系统后,桌面环境都已经预装并正常工作了。
Linux 的安装
这里以 Manjaro 操作系统为例,简要说明系统安装步骤
从 Manjaro 官网 的下载页面选择合适的版本并将
iso
镜像文件下载到本地(以 KDE 版本为例)。如果使用虚拟机,则此时新建一个虚拟机,将刚才下载的
iso
镜像装载到虚拟机上启动;若要通过U盘安装到本地机器,则可用 Rufus 软件载入镜像并以DD
模式写入U盘,然后重启计算机,注意正确设置 BIOS 以从U盘启动。在 Manjaro 的启动页面进行相关设置,若在接下来的步骤中出现驱动问题,可重回此步并将
driver
项设为non-free
。进入
live
系统后,启动安装程序,按照提示配置好各项参数,最后点击安装即可。安装完成后,重启计算机并移除U盘,在 Grub 页面选择刚刚安装的 Manjaro 操作系统。
文件系统和分区
Linux 使用的磁盘分区格式为 ext4
,而 Windows 并不支持(不会显示在资源管理器中)这种格式,因此对于双系统的用户来说,Linux 系统所占用的磁盘空间需要合理分配。Linux 将文件系统组织为一个树形结构,与 Windows 以盘符区分的方式有所不同,Linux 的所有目录都是 /
目录的子目录,这个 /
目录称为根目录。对于管理多个分区的 Linux 来说,它将各个磁盘分区挂载
到不同的目录下,分区的所有文件目录都通过挂载到的目录来访问,因此对于 Linux 文件系统来说,分区管理是透明
的。此外,对于U盘、CD等可移动介质,Linux 也是通过即时挂载、事后卸载的方式管理,这是 Linux 在文件系统上区别于 Windows 的一大特点。
Linux 普通文件系统分区格式一般用 ext4
,而用作交换区的 swap
分区则有专用的 swap
格式,提供与 Windows 虚拟页面文件类似的虚拟内存功能,只不过 Linux 的做法更加彻底。这个分区的大小一般设为与物理内存大小相等。
我们刚才提到,Linux 的目录树是从唯一的一个 /
目录出发,这似乎预示着,Linux 不能如 Windows 那样用不同的盘符来分隔不同种类的文件,但情况恰恰相反,由于 Linux 有挂载点这一说,虽然从文件系统层面上看,所有文件都组织在一个目录树下,但从物理分区上讲,在目录树上的任一节点都可以挂载不同的分区,这就使得无论如何进行分区,Linux 的文件系统除了选择一个节点挂载它们之外无需作出任何更改,并且可以实现多个 Linux 系统在某个节点共享同一份数据,或者在操作系统每次启动时为它挂载不同的分区,从而实现每次运行时都可以使用不同的数据。
另外,在 Linux 的文件系统中,以 .
开头的文件名被认为是隐藏文件,更特殊的,./
和 ../
分别意味着 当前目录
和 上级目录
,它们不是实际存在的文件,仅代表两个入口。事实上,Linux 隐藏文件的设定并非为了对某些文件进行保密,而只是将不需要显示在前台的文件加上标记,它们通常是系统和一些软件的资源文件或应用数据目录,并且用户不需要在前台看到它们。
NFS - 网络文件系统,是一套可扩展、高性能、高质量的共享文件系统,只需从一个或多个服务器上建立数据仓库,多个客户端即可通过用户接口访问数据并加载到本地空间,如同本地的可插拔文件系统一般。它与普通文件系统唯一的区别在于其 I/O 请求是跨越网络完成的。
运行级别
Linux 有运行级别的概念,目前来说定义了七种运行级别:
- 停机状态
- 单用户模式
- 多用户模式(无 NFS)
- 完全多用户模式
- 保留
- X11 图形服务器模式
- 重启状态
这些运行级别分别对应着不同的服务组,这些服务项在开机时由 init
负责启动,一般这些都存储在 /etc/rc.d/rcN.d/
目录下,但有些系统并不遵循这个标准——比如 Arch。一般来说,用户常用的默认运行级别为3和5——作为服务器时通常为3,作为桌面操作系统通常使用5——当我们需要执行一些特殊操作时,可能需要手动进入单用户状态,如重置 root
用户密码等。
注:
若要恢复删除的系统文件,请进入救援模式而不是单用户模式,因为单用户模式也需要从硬盘引导启动!
不要将系统默认启动状态设为0或6,否则系统将无法正常启动,切记!
强大的终端
Linux 系统的一个非常重要的工具就是 shell,它是 Linux 用户操作计算机的桥梁,其本质是一个命令解释器(CLI),文字模式下系统启动后进入的界面就是 shell,而在图形界面中通常要通过 终端模拟器
来进入。所谓终端,指的就是这种通过 shell 进行用户交互的软件。在 KDE 下,我们使用 Konsole 终端模拟器。著名的终端模拟器还有 Terminal、Yakuake 等。而选择好终端模拟器后,我们还需要选择一个 shell ——默认情况下,系统预设 shell 是 bash ——我的选择是 Zsh。
前面提到,shell 是一个命令解释器,那么它的工作就很好定义了:接收用户输入的命令,执行它们,并输出执行结果。这就是典型的 shell 的工作模式。shell 很多预置命令都由两个字母构成——事实上,若非键盘上只有26个字母,可能现在的命令就只有一个字母了——这些命令能够执行简单的文件目录管理。
# 切换工作目录 cd ~/Documents # 列出目录下的文件/目录列表 ls [-alh] # 显示当前工作目录 pwd [-P] # 更新文件的修改日期,一般用来创建文件 touch main.c # 创建目录 mkdir test # 移动和复制文件,可用于重命名 mv a.c test/ mv a.c b.c cp a.c a.c.back # 删除文件或目录 rm a.c rm -r test/ # 创建链接文件,类似 Windows 快捷方式 ln -s ~/Documents/clang # 列出文件内容 cat a.c # 回显命令,可显示环境变量 echo Hello, $HOME.'\n'This is my Path:'\n'$PATH
除了一些特殊命令外,shell 中运行的命令通常都是实际存在的程序,shell 会从用户的 PATH
环境变量中定义的路径查找命令并执行,路径之间以 :
分隔。通常,PATH
环境变量并不包括 当前目录
,因此,若要执行目录下的程序,应以 ./
开头。
作为命令解释器,shell 除了能够解释执行用户输入的指令外,也能够执行脚本文件。下例是一个典型的 shell 脚本:
#!/usr/bin/bash # 我是注释 # 巧了,我也是 echo "Currently working in `pwd`" echo "Host: `hostname`" ret=yes ping -c 2 www.baidu.com > /dev/null || ret=no echo "Am I online? $ret" echo "Now running: $0" figlet -f standard "The end."
要运行这个脚本,可以为它指定一个解释器:
bash xxx.sh
也可以先赋予它 可执行权限
,再直接执行:
chmod +x xxx.sh ./xxx.sh。
一个特殊的脚本是,shell
在用户目录下保存的名为 .bashrc
的文件(或 .zshrc
等),它是属于 shell
的一个资源文件,这意味着每次启动用户的 shell
时,它都会预先寻找并分析此文件的内容,并执行相应的初始化命令。常见的用法包括在此文件中添加别名定义、添加环境变量配置等。
# ~/.bashrc alias ll='ls -alF' alias df='df -h' export PATH=PATH:$HOME/.local/bin
Linux 文件系统权限
对于任意一个目录,执行 ls -hl
命令并观察其输出,我们将看到,每个项目之前都有一个由十位字符构成的字符串,这代表了一个文件(或目录)的类型和权限。其形式为 -rwxr-xr-x
,第一位代表类型(-/d/l/c/b/s/p),后面九位每三个一组,每位分别代表其读、写、可执行权限,每组分别表示所属用户、所属组和所有人的权限。
Linux 中用户与组的概念比 Windows 要深刻得多,除普通用户外,最常涉及的是 root
用户和 wheel
组。在 Linux 下,root
用户是系统的最高管理员,拥有操作任何文件目录的权限,也就有着误操作导致系统崩溃的风险,也可能因执行恶意程序导致系统被劫持,因此一般情况下,我们不会以 root
身份作业。但与此同时,很多任务又需要这些权限才能执行,比如安装应用或更改启动项,于是 sudo
命令提出了一种普通用户临时获取 root
权限的可能,它允许用户临时获取权限来执行某些操作,并且可以配置用户/组使用 root
身份可以执行哪些操作。一般情况下,作为桌面版用户,我们也不必去细分这些权限,所以可以简单地将自己加入到 wheel
组即可拥有 sudo
的权限,wheel
组正是预设的拥有 sudo
权限的组。
软件包管理
与 Windows 系统不同,尽管 Linux 也允许用户直接运行可执行文件,但这些软件通常会因为依赖问题等原因而不能正常工作。查找和安装应用软件最好的方式是通过软件仓库,不同的发行版通常会有不同的软件仓库,我们称之为 源
,用来查找和下载安装软件包并解决依赖关系的工具称为 包管理器
,如 Ubuntu 使用 apt
和 dpkg
,CentOS 使用 yum
和 rpm
,Manjaro 使用 pacman
等。
我们刚才多次提及 依赖
,简单来说就是指某个包使用了另一个包提供的接口,因而需要该包的支持才能运行,故安装某个包可能同时需要为它安装所有的依赖,卸载某个包又要考虑有没有哪些包是依赖它而运行的,同时还要注意是否存在多个包依赖着同一个包的不同版本。这些检查和操作是必要的,否则久而久之你将不知道自己的系统上哪些包是无用的,哪些是不可或缺的,也就不敢轻易安装和卸载应用了。
用户获取软件包的来源通常是官方或官方信任的镜像站点,这些通常叫做软件仓库或 源
。作为天朝子民,为了加速软件包的下载,我们往往会选择国内的镜像源,如清华源、中科大源、华为云等。更改系统镜像源的操作这里不作细讲,我们以 apt
和 pacman
为例,简要介绍软件安装、卸载和搜索等操作。
# 更新数据库 sudo apt update sudo pacman -Sy # 以更新软件包的方式更新系统 sudo apt upgrade sudo pacman -Su # 安装 vim sudo apt install vim sudo pacman -S vim # 卸载 libreoffice sudo apt remove libreoffice* sudo pacman -R libreoffice*
编辑器之神:VIM
Linux 终端若无法承担文字编辑任务,便担不得强大之名。事实上,若论终端文字编辑工具,nano
、vim
、Emacs
均为此类,但 nano
侧重简单易用,而 vim
和 Emacs
则拥有着强大的功能。较之 Emacs
提供了丰富的组合键,vim
则更倾向于使用单键执行操作。若您更喜欢 Emacs
的优雅,请暂且移步 Emacs
教程;若您与我同样选择 vim
,欢迎继续阅读。
在终端下启动
vim
# 启动 vim [并打开文件 xxx.sh] vim [xxx.sh]
vim
各种模式启动
vim
后,默认进入的是NORMAL
模式,即普通模式(有时也称命令模式),在此模式下可以移动输入光标,执行单键命令,并可键入:
激活底部命令模式。在此模式下,h
/j
/k
/l
分别表示左/下/上/右。当按下i
/a
(I
/A
) 时,将从当前光标所在字符之前/后(行首/行尾)进入INSERT
模式,即插入模式。若按下v
/V
/Ctrl
+v
时进入VISUAL
/VISUAL LINE
/VISUAL BLOCK
模式,即视图模式。在普通模式下,还可以按x
/d
执行删除、按y
执行复制、按gg
/G
/^
/$
跳转至开头/结尾/行首/行尾、按u
/Ctrl
+r
执行撤销/重做操作。在
INSERT
模式下能够执行字符输入操作,完成输入后按Esc
结束。在VISUAL
模式下可以移动光标进行文本选取,并进一步执行d
/y
等完成删除/复制等操作。在任何模式下,您都可以按Esc
返回到普通模式,并请记住,vim
区分大小写,因此时刻注意您的键盘状态!
在使用vim
编辑文档和代码时,请注意在普通模式和插入模式之间灵活切换,以将输入操作碎片化,从而能够更灵活地执行撤销与重做操作,因为vim
将每次从进入插入模式开始,到按Esc
回到普通模式的一整个过程认为是一次插入操作。当编辑完成后,可以键入:wq
或:x
来保存文件并退出vim
。如果要丢弃修改,不保存而直接退出,可以键入:q!
。vim
查找与替换在普通模式下,按下键盘上的
/
键即进入查找模式,此时在底部会显示键入信息,支持正则表达式,按下Enter
完成键入并跳转到查找到的高亮结果。如需暂时关闭高亮,请在底部命令模式下执行nohl
命令。vim
的替换命令更加强大。其基本格式为:[range]s/from/to/[flags]
,其中冒号表示进入底部命令模式,range
表示范围(行),from
表示查找目标,可以是正则表达式,to
表示替换成的字符串,flag
表示选项:g
-替换所有 /c
-替换前确认 /e
-忽略错误。例:# 将每一行的所有 `Flag` 替换为 `flag` :%s/Flag/flag/g # 将第6行的第一个 `int` 替换为 `double` :6s/int/double/ # 将从第8行到倒数第5行的所有数字替换为 `num` :8,$-4s/\([0-9]\)\+/num/g # 将光标所在行的下一行的所有单词删除 :.+1s/\([a-z|A-Z]\)\+//g
vim
多文件编辑多窗口模式:在终端中键入
vim -o2 [xxx.cpp [yyy.cpp]]
可将视图水平分割成上下两个窗口,若参数使用大写字母O
则为竖直分割。此外,在vim
的普通模式下,键入:split
可水平分割为上下两个窗口查看当前文件,或键入:vsplit
竖直分割。当然,若split
命令有参数,则尝试打开文件。在多窗口状态下,按下组合键Ctrl
+w
激活窗口操作,此时可按h
/j
/k
/l
切换窗口,并可按r
/R
/x
/X
交换窗口位置。多标签模式:在终端中键入
vim -p2 [xxx.cpp [yyy.cpp]]
可激活vim
的多标签页模式,或在vim
中执行:tabe [file.txt]
建立新的标签页(并在新标签页中打开文件file.txt
)。在此状态下,键入gt
/gT
可顺序/逆序遍历标签页。vimrc
资源文件与
shell
类似,vim
在启动时会载入一个资源文件,并分析执行资源文件中预定义的所有命令。这一般包括vim
的个性化设置如视图布局和主题等,还会有一些vim
插件的配置数据,有时我们也会在其中编写一些按键映射和函数定义,用以执行一些自动化操作,特别是编译和运行程序。要配置一个适合于自己的vimrc
文件,请移步相关教程和文档,这里不作赘述。
使用 Linux 溜起 C/C++
众所周知,C语言程序调试分两步走:码代码、跑程序,当然,这是因为中间一系列步骤都被各大 IDE 简化了。即使现在,手里握着 Linux 的我们依旧可以选择使用 IDE,并且我们也确实有许多优秀的候选项。不过这篇文章并非介绍这些 IDEs for Linux,作为开箱即用的软件套件,它们几乎不需要被介绍。即使您还是希望选择一个 IDE,最好也了解一下背后的过程。
简单来说,C语言从代码到目标程序的构建过程分为预处理、编译、汇编、链接四步,在没有 IDE 帮助的情形下,我们就需要手动完成这些操作。幸运的是,编译器通常允许我们忽略中间的具体步骤,直接从输入源代码到输出目标程序。自然,我们也可以选择输出中间文件,这在很多情况下往往十分必要。假如我们现在已经拥有一个使用 vim
或其他任何编辑器编写的源代码文件 hello.c
,我们可以在 shell
中使用 GCC 工具(GNU Compiler Collection)完成编译操作:
# 若无 GCC 套件,先安装 sudo apt install gcc sudo pacman -S gcc # 将 hello.c 编译成目标程序(`-o` 选项可指定输出文件名) gcc hello.c [-o hello.out] # 执行编译输出的可执行文件(参数) ./a.out [argument list] # 只进行到汇编,输出 obj 文件 gcc -c hello.c [-o hello.o] # 只进行到编译,输出汇编代码文件 gcc -S hello.c [-o hello.s] # 只作预处理,从标准输出展示结果(可重定向到文件) gcc -E hello.c [> hello.txt] # 编译过程中产生调试信息 gcc -g hello.c # 显示所有警告信息 gcc -Wall hello.c # 优化级别 [0-4] gcc -O2 hello.c # 更多用法请参考 `man gcc`
在进行大型项目、多文件的软件开发过程中,逐个编译源文件是非常不明智的,这时候可以考虑采用
makefile
自动化编译过程,通过分析文件之间的依赖关系,确保所有文件保持最新,同时又不执行冗余的操作。比如当某一个或多个文件更改时,不必重新处理所有源代码,而只需要重新编译修改的文件和引用它的文件。如您正有相关需求,请移步makefile
相关文档。
到这里,我们已经完成了将源代码构建为目标程序的过程,如果编译时加入了调试信息,那么现在可以使用 gdb
进行调试工作——尽管这也许会相当麻烦。我们可以通过 gdb -h
和 man gdb
命令来获取它的参数和命令以及其他介绍,这里给出一个示例。
# 启动 gdb (并打开目标程序) gdb [a.out]
gdb
相关命令:
(gdb) file a.out 载入可执行文件 (gdb) list 列出源代码 (gdb) break 6 在第六行添加断点 (gdb) run hello world argu3 argu4 运行待调试程序并给出参数列表 (gdb) print str 输出当前变量 str 的值 (gdb) next 执行下一条语句,不进入函数 (gdb) step 执行下一条语句,进入函数内部 (gdb) display i 监视变量 i (gdb) continue 继续运行,直到下一个断点 (gdb) delete 1 删除编号为1的断点 (gdb) delete display 1 删除编号为1的监视点 (gdb) kill 终止程序执行 (gdb) quit 退出调试器
暂停笔于此,如有疏漏,欢迎指正!