跳转至

Linux

约 3543 个字 35 行代码 预计阅读时间 12 分钟

前置知识

  • 有一台自己的电脑
  • 愿意动手实践的决心(多尝试)
  • 做好笔记整理与总结的能力(遗忘后便于快速回忆)

序言 Prologue

What Is Linux?

Linux 是一种自由和开放源码的类 UNIX 操作系统,其内核由 Linus Torvalds 在 1991 年发布。

Linux 也是自由软件和开放源代码软件发展中最著名的例子,只要遵循 GNU,任何个人和机构都可以自由地使用 Linux 的所有底层源代码,这使得它得到来自全世界软件爱好者和组织的开发支持。

Linux 以各种形式被广泛应用在各个领域,包括但不限于:

  • 服务器、主机、超级计算机
  • 嵌入式系统(机顶盒、移动设备等)
  • 基础设施(红绿灯、工业传感器)

Linux Distros

我们平时使用的“Linux”严格来说是 Linux 发行版本,而 Linux 狭义上单指操作系统的内核。

发行版本在内核的基础上还包括安装工具、系统配置、图形桌面界面、各种 GNU 软件等,使得这个系统能够适用于各种使用目的。

常见的 Linux 发行版有 Debian、Ubuntu、Fedora、CentOS、Arch Linux 等。不同的发行版使用的软件不同,有些发行版本是设计成专门的目的(比如 Kali 用于网安)。

我们一般使用的虚拟机的发行版为 Ubuntu 20.04。

Ways to Use Linux

我们接触 Linux 的方式通常有以下几种:

  • 安装 Linux 系统(单系统、Windows & Linux 双系统)
  • WSL(英语:Windows Subsystem for Linux)(Recommended)
  • 虚拟机(Virtualbox、Docker)
  • 服务器远程连接(SSH、RDP)

我推荐有条件的同学给电脑装一个Linux系统。这样你就能在各种配置中度过一段漫长而有趣的时光了

Basic Concepts

  • GUI:Graphical User Interface. 图形用户界面,如其名。
  • CLI:Command-Line Interface. 命令行界面,如其名。
  • Shell:一种软件,我们可以将它视为“用户到内核之间的中介”,它接受并解析(英语:Parse)用户输入命令行的指令,并调用内核所提供的对应服务。Shell 的发明是因为内核并不提供与用户交互的方式。

OxQZi

其实 Shell 还分为图形界面和命令行界面两种,比如 Windows 的文件浏览器、程序管理器都可以算是 GUI Shell,但用 Linux 时我们一般说的都是 CLI Shell。

常见的 Shell 包括 sh、bash、zsh、fish 等。

  • Terminal:终端的名字来源于它在用户和机器交互过程中所处的位置:用户在终端输入、机器通过终端输出,现在我们已经不再需要专门的硬件充当终端,而是利用一个程序来模拟其行为。当我们打开一个终端模拟器(如 Windows 的 cmd,Linux 的 Konsole、gnome-terminal)时,一个 Shell 随即被运行,我们就可以通过这个 Shell 所提供的 CLI 输入指令了。

一个简单区分上述术语的回答:https://askubuntu.com/a/506880。

Shell 101

打开终端,界面上会出现类似于下面样子的提示符:training@SAST-Training:~$

从左到右依次是当前身份 training,主机名 SAST-Training,和当前工作目录 ~ 以及一个美元符号(fish 下是 > 号),这个美元符号表明当前用户不是 root

如果你用 root 身份打开 Shell,呈现的提示符大概是这样 root@SAST-Training:~#。即 # 符号表明了 root 身份。

How Does Shell Run Commands?

在 Shell 中你每次输入一个命令,这个命令被 Shell 解析、运行,并将结果输出到终端。

training@SAST:~$ echo "Hello SAST!"
Hello SAST!

Shell 的命令由空格分割,第一个是要运行的程序(如上例 echo),后面跟它的参数(如上例 "Hello World!")。

注意到我们把想输出的 Hello SAST! 用引号扩了起来,这样本来空格分隔的两个词就合并成了一个参数。(其实这个例子中并不需要将它们合并,因为 echo 指令可以接受多个字符串输入。)

可是 Shell 怎么知道 echo 指的是什么呢?这些程序都是 Shell 内置的吗?其实当 Shell 遇到它不认识的程序关键字时,会查询环境变量 $PATH,在里面记录的路径中寻找 echo 这个程序,如果找到便执行。如果我们想知道这个程序实际所在的位置,可以使用 which echo

training@SAST:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:
/usr/sbin:/usr/bin:/sbin:/bin
training@SAST:~$ which echo
/usr/bin/echo

所以当我们执行 echo "Hello" 时,实质上等价于执行 /usr/bin/echo "Hello",后者明确指定了要执行程序的所在目录和它的名字。

Basic Commands

接下来我们看一些基本指令。

Command Description
目录相关
pwd 当前目录
cd 切换目录
ls 查看目录列表
mkdir 创建目录
find 在层级目录下搜索文件
文件相关
touch 创建
mv 移动(可用于重命名)
cp 拷贝
rm 删除
chmod 更改文件权限
chown 更改文件所属
echo 输出提供的文本
file 查看文件类型
cat 将文件内容输出到标准输出
用户和组相关
useradd 创建用户
groupadd 创建组
passwd 更改密码
chpasswd 批量更改密码
su 一般用于切换用户
sudo 一般用于执行 root 权限指令

其他一些可能用到的指令包括 greppssystemctlip 等。

File System

现在我们可以用 lscd 来翻阅系统里的文件了!

首先是一些基本的表示:/ 表示根路径,~ 表示家路径(/home/username/,如果是 root 则为 /root/),. 表示当前目录,.. 表示上一级目录。这些表示省去了很多写绝对路径的麻烦。你可以试试 cd 到这些地方,然后用 ls 查看目录里的内容。

我们来看看根路径下都有哪些文件夹:

Screenshot from 2021-07-11 17-20-03

  • /etc 目录是系统根路径下最重要的目录之一,它是用来存储操作系统文件的公共区域,比如 /etc/sudoers/etc/passwd 分别记录了拥有 root 权限的用户、系统内的所有用户信息。
  • /var 目录是系统的服务或应用频繁写入的地方,比如 /var/log 存储了程序的 log 文件。
  • /tmp 里是一些程序只需要访问一两次的文件,每当系统重启时,这里的文件都会被清空。注意这个文件夹默认可被任何用户写入。
  • /home 这个文件夹下是各个用户的家目录。
  • /mnt 是数据卷的挂载点;通过 USB 等接口连接的外部媒体也可能出现在 /media 文件夹中。
  • /srv 存放这个服务器提供的服务所需的文件(如网站资源)。

Permissions

Linux 系统支持多用户同时登录并执行各自的任务。为了对不同用户进行管理控制,可以定义用户组(英语:group)来划分不同的访问权限。我们通过具体例子来理解。

training@SAST: /Documents/sast-training $ ls -l
total 8
drwxrwxr-x 2 training training 4096 7月  11 22:31 folder
-rw-rw-r-- 1 training training    0 7月  11 20:16 hello.txt
-rwxrwxr-x 1 training training   27 7月  11 22:33 program.sh

对于目录中每一项开头的 "-rw-rw-r--"(以文本 hello.txt 为例)字样,下图给了一些解释:

IMG_2021-07-11T22-47-19

  • 开头第一个字符是用于特殊权限的 flag,它来表明该文件的一些特殊属性如文件夹、连接等。
  • 接下来九个 flag 每三个为一组,分别代表所属用户、所属组、所有其他用户对于这个文件的 r(read)、w(write)、x(execute) 三种访问的权限。
  • 除了用 rwx 字符来表示外,还可以用二进制编码表示,其中 r 为最高位 4,w 中间位 2,x 最低位 1。例如可读写可执行的权限编码为 7,可读写不可执行为 6,可读可执行为 5 等。

对于一些重要文件,你大概不希望组内其他用户或者任意用户对它有过多的访问权限;或者对于一些刚写好的脚本文件默认为可读写不可执行,你希望能够获得执行它的权限。这时我们可以通过 chmod 指令来改变文件的权限设置。

chmod +x script.sh     # 给脚本添加可执行权限(默认对于任何人 (a))
chmod 777 public.py    # 让文件可被任何人读写执行,777 等价于 a+rwx
chmod o-rw journal.txt # 禁止组外用户 (o) 的读写

Shell Operations

以下是一些 Shell 中能用到的操作符。最好还是结合实际应用来掌握。

Operator Description Example
& 允许命令在后台执行 cp -r ./here ./there &
&& 执行多条指令,逻辑和 C++ 类似 wget someurl/install.sh . && ./install.sh
> 重定向输出 echo "Hello" > hello.txt
< 重定向输入 ./main < in.txt
>> 重定向输出并采取“追加”模式 echo cirno >> visitors.txt
| 连接前后两个程序的输出和输入 ls ~/Documents | grep note.txt

Read the Manual

man <command-name>

man 指令是了解各种指令具体用法的最快途径,绝大多数的指令和软件都会有对应的 Manual 提供查看,在里面你可以看到指令的名称来源、作者、描述和用法等等。

man 所打开的界面支持多种浏览方式,Vim 的 J/K、方向键、回车键、翻页键等都可以使用,并且支持搜索功能。

比如我们想了解 ls-h 选项的作用,可以在 man ls 中输入 /-h 并回车,搜索到的 -h 选项就会高亮显示,继续回车找到下一个结果。/ 是向后搜索,而 ? 是向前搜索。

如果你想查看帮助的软件凑巧没有对应的 Manual,你总可以试试在指令名后加上 -h / --help 选项,通常来说命令输出错误时它就会有 Usage 的提示。

类似的软件还有 tldr(too long; didn't read)、cheat(cheatsheet)、fuck 等,它们是精简版的 man,提供了指令的常见用法。

SSH

现在我们回到 SSH 上来。

Executing Commands

SSH 可以直接远程执行命令而不需要连接到远程的 Shell 中,在连接命令后加上需要执行的命令:

ssh foobar@server [command]

Copying Files

scp 指令可以从远程拷贝文件到本地/从本地拷贝文件到远程,基本格式是 scp <from> <to>。如果要拷贝一个文件夹,应该使用 flag -r 表示递归深入目录。

# 将本地当前目录的 test.zip 拷贝到远程的 ~/test.zip
scp test.zip training@153.223.56.12:~/test.zip 
# 将远程的 data.csv 拷贝到本地当前目录
scp training@152.32.34.12:~/data.csv . 

Config File

每次连接服务器都要输入用户名、IP 和端口未免过于繁琐,我们可以通过编辑 SSH 配置文件来简化命令。这个配置文件位于家路径的 .ssh 文件夹下,名字为 config(如果不存在需自己创建),即 ~/.ssh/config。对于 Windows 系统而言,这个 .ssh 文件夹位于用户目录下 C:\Users\<username>\.ssh\config。配置文件写法如下:

HOST sast
    HostName 152.136.177.53
    Port 8000     (默认22,此时不需要指定)
    User root

这样每次我们想连接到 root@152.136.177.53 -p 8000 时只需要输入 ssh sast 即可。

这个配置文件同样适用于 scp 命令:

# 前一小节例子的简略版
scp test.zip sast:~/test.zip 
scp sast:~/data.csv . 

Key Authentication

SSH 配置文件并不能指定登录时的密码(显然这样会很不安全),所以我们登录时还是要输入密码。能不能连密码都不用输入?

利用密码学中的公钥-私钥非对称加密机制,我们只需要在服务器中预存好自己的公钥,就可以在登录时自动化验证流程而免去密码。这个过程的关键是向服务器 Alice 证明自己是持有私钥的那个客户端 Bob:Alice 用 Bob 预存的公钥加密一个用于验证的串发给 Bob,Bob 用私钥解密得到这个串后发给 Alice,就能证明自己确实持有与公钥对应的私钥。

Screenshot from 2021-07-15 10-59-22

密钥生成

ssh-keygen

按照命令行提示流程,默认在 ~/.ssh 下生成公钥 id_rsa.pub 和私钥 id_rsa,后者需要妥善保存。通过 ssh-keygen -y -f ~/.ssh/id_rsa 检验密钥的存在。

在服务器中存放公钥

在接受 SSH 连接请求时,服务器的 SSH 会在目标用户的 ~/.ssh/authorized_keys 中查找公钥。因此我们需要将自己的 id_rsa.pub 中的内容追加到服务器的 authorized_keys 中。

cat ~/.ssh/id_rsa.pub | ssh training 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys' 
# Windows 下路径为 ~/.ssh/id_rsa.pub

上面的命令完成了将本地公钥保存到远程服务器的过程,经过之前的学习,你能理解这个命令是如何执行的吗?

ssh-copy-id 提供了更简便的解决方案:ssh-copy-id -i ~/.ssh/id_rsa.pub training

Basic Tools

Package Manager

软件包管理系统是在电脑中自动安装、配置、卸载和升级软件包的工作组合。使用软件包管理系统可以大大简化在 Linux 发行版中安装软件的流程。常见的软件包有两种类型:deb 软件包(由 dpkg 和它的前端 apt 管理,使用于 Debian、Ubuntu)和 RPM 软件包(由 dnf、yum、ZYpp 等前端管理)。

绝大多数的 Linux 发行版或类 Unix 系统都有它的包管理器,Ubuntu 有 apt,Arch Linux 有 pacman,macOS 有 Homebrew

包管理器的指令一般都很符合直观,如果失败了可以通过 man 或者 help 查看用法。

系统中包管理器所使用的仓库往往默认位于国外,这使得每次从仓库拉取东西时耗费很长时间或者甚至连不上。好在我们国内有许多的镜像源,比如清华的 TUNA,访问 https://mirrors.tuna.tsinghua.edu.cn/help 可以找到 Ubuntu 在内的各种仓库镜像源配置方法。

Homebrew 的安装方法:

/bin/bash -c \
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Vim

vimtutor explains it all. vimtutor -g zh for Chinese learner.

hottest_editors

tmux

我们每次打开终端或是 SSH 登录远程服务器时,都是创建了一个会话(英文:session)来进行临时的交互,此时窗口(或连接)是和它开启的进程(比如 Shell)绑定在一起。当我们关闭窗口或者断开连接时,对应的进程也随之终止了。

为了在会话结束后其开启的进程还能继续进行,我们需要先进行"解绑",在后续需要时再重新进行绑定。tmux 完成的就是这样一个任务。

tmux            # 创建新的 tmux 会话
tmux detach     # 分离当前 tmux 会话,快捷键 Ctrl+B D
tmux ls         # tmux list-session
tmux attach -t <session-name> # Sessions are labeled by numbers by default
tmux kill-session -t <session-name>

除了能够让任务持续进行,tmux 还有一个很重要的功能是分窗口和分屏。

Ctrl+B %      # Split horizontally
Ctrl+B "      # Split vertically
Ctrl+B 方向键  # Switch between panes
# ...

这一系列操作的快捷键基本上都是 Ctrl+B xxx,请自行学习掌握。

附:https://tmuxcheatsheet.com/

后续拓展

想要学习更多 Linux 内容?

  • TryHackMe "Linux Fundamentals" Series https://www.tryhackme.com
  • Missing Semester https://missing.csail.mit.edu/

参考资料

  • 2021 暑培讲义 by JuneTheRiver
  • 菜鸟教程 https://www.runoob.com/linux/linux-tutorial.html