跳转至

基础工具学习

约 4107 个字 55 行代码 2 张图片 预计阅读时间 14 分钟

本章主要介绍一些 Linux 中的基础工具,强烈建议学习该部分时在 Linux 系统上自己动手操作一遍

Shell

简单来说,Shell 脚本就是一个包含一系列命令的文本文件

创建执行 Shell 脚本

在 Linux 系统上,脚本文件通常是后缀为 .sh 的文件,可以使用 chmod +x script.sh 给脚本添加执行权限,然后使用以下命令之一来执行脚本:

./script.sh
bash script.sh
source sctipt.sh
三种不同执行方式的差异

第一种方式 ./script.sh 与第二种方式 bash script.sh 均会在一个新的子 Shell 中执行脚本,这意味着脚本中的变量和环境设置不会影响当前 Shell 的环境。而第三种方式 source script.sh 会在当前 Shell 中执行脚本,因此通常用于设置当前 Shell 的环境变量或执行一些需要在当前 Shell 中生效的命令。

第一种方式要求 script.sh 具有可执行权限,而第二种和第三种方式不需要。

同时,若当前 Shell 不是 bash,而是 dash (Debian 系)、zsh 等其它 Shell,那么第一种和第三种方式会使用当前 Shell (可通过 $SHELL 变量查看)运行,而第二种方式强制使用 Bash 运行。

Shell 脚本语法

Shell 脚本中的所有语法都与 Shell 的语法一致,接下来简单介绍一些相对复杂的 Shell 算法

定义函数

#define the function in a shell script
mdc() {
    mkdir -p "$1" #character with $ will be reserved
    cd "$1"
}

逻辑控制

在 Shell 脚本中,流程控制语句是用于根据条件执行不同代码块或循环执行一组命令的关键工具。常见的流程控制语句包括:if(条件语句)、for(循环语句)、while(循环语句)等。下面是对这些基本流程控制语句的详细介绍及其用法。

if 语句

if 语句用于根据条件执行特定的命令。条件可以是比较两个值、检查文件是否存在等。

if [ condition ]
then
    # 如果条件为真,执行的命令
elif [ another_condition ]
then
    # 如果另一个条件为真,执行的命令
else
    # 如果所有条件都不满足,执行的命令
fi

示例:

#!/bin/bash
if [ $1 -eq 10 ]; then
    echo "参数等于 10"
else
    echo "参数不等于 10"
fi

常见的条件判断操作符:

  • 整数比较

    • -eq : 等于(equal)
    • -ne : 不等于(not equal)
    • -gt : 大于(greater than)
    • -lt : 小于(less than)
    • -ge : 大于或等于(greater than or equal)
    • -le : 小于或等于(less than or equal)
  • 字符串比较

    • =, == : 等于
    • != : 不等于
    • <, > : 比较字符串的字典序(需使用 [[ ... ]]
  • 文件测试

    • -e : 文件存在
    • -f : 普通文件存在
    • -d : 目录存在
    • -r : 文件可读
    • -w : 文件可写
    • -x : 文件可执行

for 循环

for 循环用于重复执行一组命令,直到完成指定次数或遍历完列表中的所有元素。

for var in list
do
    # 循环体
done

while 循环

while 循环根据给定的条件重复执行某些命令,直到条件不再满足。

while [ condition ]
do
    # 条件为真时执行的命令
done

简单的 while 循环

#!/bin/bash
count=1
while [ $count -le 5 ]
do
    echo "计数: $count"
    ((count++))  # 或者使用 count=$((count+1))
done

读文件的每一行

#!/bin/bash
while read line
do
    echo "读取到的行: $line"
done < inputfile.txt

breakcontinue

  • break 用于跳出循环。
  • continue 用于跳过当前循环的剩余部分,继续下一个迭代。

参考链接:

Git

Git 是一款分布式版本控制系统,由 Linus Torvalds 开发,用于高效管理项目代码的变更。它的核心功能是记录文件的历史修改,支持多人协作开发,并允许随时回溯到任意版本。强烈推荐阅读 Git Book 来深入了解 Git 的使用。

Git 的核心功能包括:

  1. 版本追踪:每次修改提交(commit)都会生成唯一快照,便于追溯问题或恢复代码。
  2. 分支管理:开发者可创建独立分支(branch)进行功能开发,完成后合并(merge)到主分支,避免冲突。
  3. 分布式协作:每个成员拥有完整的代码仓库,支持离线工作,通过推送(push)/拉取(pull)与团队同步。

Git 是开发者必备工具,在很多项目的开发中,均需要使用 Git 进行版本控制,并通过 Github/Gitlab 等平台进行协作开发,学习基础的 Git 命令是必要的。

基本概念

  1. 快照(napshot): git 的本质就是对某些特定的目录进行版本记录保存,也就是拍摄快照,使用者可以依据这些快照进行相应的版本控制操作。
  2. 暂存区: 是开发者暂时存储自己对程序修改的地方,允许开发者有选择性地将工作区中不同的更改分阶段地准备纳入下一次提交。
  3. 本地仓库: 是本地存储整个 git 仓库进行版本控制的目录。
  4. 远程仓库: 创建在如 Github 等软件的仓库,用于统一保存 git 仓库,作为开发的中枢。所有开发者将各自提交推送到仓库中,同时从仓库中拉取最新版本或别人的提交。
  5. 分支(Branch): 分支是对同一个仓库进行版本控制的不同时间线,可以根据开发者、使用功能的不同创建不同的分支,不同的分支之间相互独立,但是也可以进行合并等操作。
  6. HEAD: 是一个指针,指向当前工作区显示的快照版本。

大致的关键操作如下图所示 alt text

基础操作

  • git help <command>: 获取某个 Git 命令的帮助文档
  • git init: 创建一个新的 Git 仓库,数据会存储在 .git 目录中
  • git status: 显示当前仓库的状态,告诉你发生了什么
  • git add <filename>: 将文件添加到暂存区
  • git commit: 创建一个新的提交

Caution

一个良好的 commit message 应该包含有效且清晰的提交信息

  • git log: 以扁平化的形式显示提交历史日志
  • git log --all --graph --decorate: 以图形化的有向无环图(DAG)形式来可视化提交历史
  • git diff <filename>: 显示工作区中的文件相对于暂存区的改动
  • git diff <revision> <filename>: 显示一个文件在不同快照(版本)之间的差异
  • git checkout <revision>: 更新 HEAD 指针(如果检出的是一个分支,则同时切换当前分支)

分支与合并

  • git branch: 显示所有分支
  • git branch <name>: 创建一个新分支
  • git checkout -b <name>: 创建一个新分支并立即切换过去
    • 等同于 git branch <name> 加上 git checkout <name> 两条命令
  • git merge <revision>: 将指定的分支/版本合并到当前所在的分支
  • git mergetool: 启动一个图形化工具来帮助解决合并冲突
  • git rebase: 将一系列提交(补丁)应用到另一个新的基底上(变基)

远程仓库

  • git remote -v: 列出所有已配置的远程仓库
  • git remote add <name> <url>: 添加一个新的远程仓库
  • git push <remote> <local branch>:<remote branch>: 将对象推送到远程仓库,并更新远程分支的引用
  • git branch -u <remote> [<branchname>]: 在本地分支和远程分支之间建立追踪关系
  • git fetch: 从远程仓库抓取对象和引用(但不合并)
  • git pull: 从远程仓库抓取并合并,大致等同于 git fetch 加上 git merge
  • git clone: 从远程仓库下载一个完整的仓库副本

撤销操作

  • git commit --amend: 修改最后一次提交的内容或提交信息
  • git reset HEAD <file>: 将文件移出暂存区(Unstage)
  • git checkout -- <file>: 丢弃在工作区中对某个文件的所有修改 `

参考链接:

Tmux

命令行的典型使用方式是,打开一个终端窗口(terminal window,以下简称"窗口"),在里面输入命令。用户与计算机的这种临时的交互,称为一次"会话"(session)。重要的一点是,窗口与其中存在的进程是相互依存的,打开窗口,会话开始,关闭窗口会话就会结束,会话内部的进程也会随之终止

Tmux 就是让会话与窗口解绑的工具

这在使用 SSH 连接远程服务器进行开发时非常重要。这意味着即使断开 SSH 连接或关闭终端,tmux 仍能保持你的会话运行。重新登录后,只需恢复会话,之前的所有工作(如运行中的程序、编辑的文件)都会原样保留。 我们强烈建议在 SSH 连接到远程服务器进行开发时使用 tmux 新建会话后在终端运行程序,而不是直接在 SSH 连接后得到的终端中运行程序。

基础操作

<C-b> 指的是按下 Ctrl + b 的组合键

会话 (Sessions)

  • 一个会话是一个独立的工作区,可以包含一个或多个窗口。
  • tmux 启动一个新会话。
  • tmux new -s NAME 启动一个命名为 NAME 的新会话。
  • tmux ls 列出当前所有会话。
  • tmux 中,输入 <C-b> d 会分离 (detach) 当前会话。
  • tmux a 附加 (attach) 到上一个会话。你可以使用 -t 标志来指定附加到哪个会话。

窗口 (Windows) - 相当于编辑器或浏览器中的标签页,它们是同一个会话中视觉上相互隔离的部分。

  • <C-b> c 创建一个新窗口。要关闭它,只需通过输入 <C-d> 来终止窗口中的 shell 进程即可。
  • <C-b> N 切换到第 N 个窗口。请注意窗口是有编号的。
  • <C-b> p 切换到前一个窗口。
  • <C-b> n 切换到后一个窗口。
  • <C-b> , 重命名当前窗口。
  • <C-b> w 列出当前所有窗口。

窗格 (Panes) - 类似于 Vim 的分屏,窗格允许你在同一个可视化界面中拥有多个 shell。

  • <C-b> " 水平分割当前窗格。
  • <C-b> % 垂直分割当前窗格。
  • <C-b> <direction> 移动到指定方向的窗格。这里的方向指箭头键。
  • <C-b> z 切换当前窗格的全屏/非全屏模式 (zoom)。
  • <C-b> [ 进入回滚模式。然后你可以按 <space> 键开始选择,按 <enter> 键复制所选内容。
  • <C-b> <space> 在不同的窗格布局之间循环切换。

htop

htop 是一个交互式的进程查看器和系统监视工具

alt text

htop 分区介绍

  1. 最上方为 CPU 核心占用情况,其中红色部分表示处在内核态,绿色部分表示处在用户态
  2. 上左区:显示了 CPU、物理内存和交换分区的信息;
  3. 上右区:显示了任务数量、平均负载和连接运行时间等信息;
  4. 进程区域:显示出当前系统中的所有进程;
  5. 操作提示区:显示了当前界面中 F1-F10 功能键中定义的快捷功能。

分区

Memory Bar

  1. 绿色的表示已经使用内存情况
  2. 蓝色的表示用于缓冲的内存使用情况
  3. 黄色的表示用于缓存的内存使用情况

Process Panal

S:进程的运行情况

  1. R 表示正在运行
  2. S 表示休眠
  3. Z 表示僵死状态
  4. N 表示该进程优先值是负数
htop 常用快捷键
快捷键 功能描述
F1h 显示帮助
F2S 进入设置菜单
F3/ 搜索进程
F4\ 过滤进程 (只显示匹配项)
F5t 显示/隐藏进程树
F6> 选择排序字段
F7[ 降低进程优先级 (增加 nice 值)
F8] 提高进程优先级 (减少 nice 值)
F9k 终止进程
F10q 退出 htop
空格键 标记/取消标记进程 (用于批量操作)
u 按用户筛选进程
H 显示/隐藏用户线程
K 显示/隐藏内核线程
P PU 使用率排序
M Memory 使用率排序
T Time (运行时间) 排序

Vim

Vim Editor Mode

A model editor: Has diff operating mode 使用 vim <filename>使用 vim 编辑器进行编辑 : help <content> 查找 command 模式下的命令含义

Vim 主要有三种编辑器模式:

  1. 正常模式(Normal mode):启动 Vim 时的默认模式。用于执行命令,同时可以方便地进行微调。
  2. 插入模式(Insert mode):用于文本输入。可以通过以下命令进入插入模式。
  3. 可视模式(Visual mode):用于选择文本,可以用来复制或剪切。

Tip

  1. 命令前加数字,就是执行该操作几次
  2. u 代表撤销操作,在 insert 模式下就加上 ctrl
  3. 命令乘二代表对整行操作
  4. 命令后加 i 代表对整个括号内的内容进行操作
  5. 小写代表下、前,大写代表右、后

插入模式 (Insert)

从正常模式进入插入模式

  • i 进入插入模式,允许你在光标前输入文本。(Insert)
  • I 在当前行的行首插入文本。
  • a 在光标后插入文本。
  • A 在当前行的行尾插入文本。
  • o 在当前行下方插入新行。(Open)
  • O 在当前行上方插入新行。

从插入模式返回正常模式

  • Esc 键返回正常模式。

正常模式 (Normal)

  1. 移动光标

    • h: 向左移动一个字符。
    • j: 向下移动一行。
    • k: 向上移动一行。
    • l: 向右移动一个字符。
    • 0: 移动至当前行的行首。
    • $: 移动至当前行的行尾。
    • gg: 移动至文件的第一行。
    • G: 移动至文件的最后一行。
    • w:移动到下一个单词。
    • b:移动到当前单词结尾。
    • L: 移动到最后一行。
    • fo:移动到该行的第一个 o。
    • 前面增加数字可以指定执行的次数 4j:下移 4 次
  2. 删除和修改

    • x: 删除光标下的字符。
    • dd: 删除当前行。(Delete)
    • ndd: 删除 n 行(例如,3dd 删除当前行及其下两行)。
    • d$: 删除光标到行尾的所有字符。
    • u: 撤销上一次操作。
    • Ctrl + r: 重做撤销的操作。
    • c:change。删除并且直接进入 Insert 模式
  3. 复制和粘贴

    • y:复制。
    • yy: 复制当前行。
    • nyy: 复制 n 行(例如,3yy 复制当前行及下两行)。
    • p: 在光标后粘贴复制的内容。
    • P: 在光标前粘贴复制的内容。
    • .:输入上一次在输入模式下输入的内容
  4. 查找

    • /pattern: 向下查找 pattern(如字符串)。
    • ?pattern: 向上查找 pattern
    • n: 查找下一个匹配。
    • N: 查找上一个匹配。
  5. 替换

    • :%s/old/new/g: 在整个文件中替换所有 oldnew
    • :n,m s/old/new/g: 在第 n 行到第 m 行之间替换。

视觉模式(Visual)

在 Normal 模式下按 v 进入 利用移动光标方式来选择一些文本

Visual 模式类型

Vim 提供了三种不同的 Visual 模式,以适应不同的选择需求:

  1. 字符模式

    • 如何进入:在 Normal 模式下按 v
    • 作用:这是最常见的模式,可以像普通编辑器一样,一个字符一个字符地自由选择文本。光标移动到哪里,选择范围就延伸到哪里。
  2. 行模式

    • 如何进入:在 Normal 模式下按 V
    • 作用:专门用于选择整行。一旦进入此模式,你的选择会自动扩展到一整行,移动光标(用 jk)会以行为单位来扩大或缩小选择范围。非常适合复制或移动多行代码。
  3. 块模式

    • 如何进入:在 Normal 模式下按 Ctrl + v
    • 作用:这是 Vim 的一个超级强大的功能,它允许你选择一个矩形的文本块(按列选择)。

在 Visual 模式下的基本操作

一旦你使用 v, V, 或 Ctrl-v 选中了文本,你就可以对这块高亮的区域执行各种操作。以下是一些最常用的命令:

  • dx删除 (剪切) 选中的文本。
  • y复制 (Yank) 选中的文本。
  • c修改 (Change) 选中的文本。它会先删除选中的内容,然后立即进入 Insert 模式,让你输入新的内容。
  • p粘贴。如果在 Visual 模式下选中了一段文本后按 p,Vim 会用剪贴板里的内容替换掉你选中的文本。

  • >:将选中的行向右 增加缩进

  • <:将选中的行向左 减少缩进
  • =自动缩进 选中的代码行(如果配置了代码格式化)。

  • J:(在行模式 V 下) 将所有选中的行 合并为一行,并用空格隔开。

  • ~切换大小写。选中的大写字母变小写,小写变大写。
  • U:将选中的文本全部变为 大写
  • u:将选中的文本全部变为 小写

保存和退出

  • 保存文件:
    • :w: 保存文件,但不退出。
    • :w filename: 将当前文件保存为新文件 filename
  • 退出 Vim:
    • :q: 退出 Vim。
    • :q!: 强制退出,不保存更改。
    • :wq: 保存并退出。

在标准开发环境中已经安装了 vimtutor,运行 vimtutor 即可打开教程。

我们并不需要学习非常多的 vim 功能,只需能够在终端使用 vim 实现文本编辑器的常见操作即可。

正则表达式

正则表达式(Regular Expression,简称 Regex 或 Regexp)是一种用于描述字符串模式的语言。它可以用来匹配、查找、替换文本中的特定模式。正则表达式由普通字符(如字母、数字)和特殊字符(称为"元字符")组成,这些元字符赋予了正则表达式强大的模式匹配能力。

我们推荐读者跟随在线教程来学习正则表达式,并可以使用 regex101 来可视化的观察正则表达式的效果。

基础语法

元字符 描述 示例 匹配结果
. 匹配任意单个字符(除换行符外) a.c "abc", "aac"
^ 匹配字符串的开始位置 ^Hello "Hello world"
$ 匹配字符串的结束位置 world$ "Hello world"
* 匹配前一个元素 0 次或多次 ab*c "ac", "abbc"
+ 匹配前一个元素 1 次或多次 ab+c "abc", "abbc"
? 匹配前一个元素 0 次或 1 次 colou?r "color", "colour"
[...] 匹配括号内的任意字符 [aeiou] "a" in "apple"
[^...] 匹配不在括号内的任意字符 [^0-9] "a" in "a1"
\| 逻辑或(匹配左边或右边的模式) cat\|dog "cat", "dog"
{n} 精确匹配 n 次 a{3} "aaa"
{n,} 匹配至少 n 次 a{2,} "aa", "aaa"
{n,m} 匹配 n 到 m 次 a{2,4} "aa", "aaa"

特殊字符类

注意:并非所有正则表达式引擎都支持这些特殊字符类,但它们在大多数现代引擎中是通用的。

简写 等效形式 描述
\d [0-9] 匹配数字
\w [a-zA-Z0-9_] 匹配字母数字和下划线
\s [ \t\r\n\f] 匹配空白字符
\D [^0-9] 匹配非数字字符
\W [^\w] 匹配非单词字符
\S [^\s] 匹配非空白字符
\b 匹配单词边界

转义字符

在正则表达式中,一些字符具有特殊含义,如 .*+ 等。如果需要匹配这些字符本身,需要使用反斜杠 \ 进行转义。特别地,部分引擎转义规则与常见的相反,即匹配字符本身不需要转义,而使用这些元字符的属性则需要使用反斜杠 \ 转义

分组与捕获

使用括号 () 可以创建捕获组,结果将被存储在捕获变量种:

(\d{4})-(\d{2})-(\d{2})

匹配日期格式 "YYYY-MM-DD",并捕获:

  • $1 = 年(4 位数字)
  • $2 = 月
  • $3 = 日

使用(?:)可以创建非捕获组,仅起到分组作用,不会捕获结果:

(?:\d{3}-)?\d{3}-\d{4}

匹配电话号码格式 "XXX-XXX-XXXX" 与 "XXX-XXXX",但不捕获第一段的可选区号

常用正则表达式示例

  1. 邮箱验证

    ^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$
    
  2. URL 匹配

    https?://(?:[-\w]+\.)+[\w]{2,}(?:/[^\s]*)?
    
  3. IP 地址匹配

    \b(?:\d{1,3}\.){3}\d{1,3}\b
    

使用辅助工具编写正则表达式

功能较为复杂的正则表达式的纯文本形式近乎是人类不可读的。我们强烈建议在编写和分析正则表达式时使用可视化编写工具,例如 regex101。常见的可视化编写工具均支持多种语言的正则表达式的语法,同时会解析输入的正则表达式的含义,并提供了在线匹配的功能。

尝试将上述的正则表达式复制到该网站(语言选择 Python),了解这些正则表达式的结构。

正则表达式的应用

正则表达式有着广泛的应用,在终端命令,编程语言与应用搜索中均能见到。

终端命令

  • grep:文本搜索

    grep -E 'pattern' file.txt  # 使用扩展正则
    
  • sed:流编辑器

    sed -E 's/old/new/g' file.txt  # 全局替换,注意此时'/'作为分隔符也需要转义
    sed -E 's#old#new#g' file.txt  # 也可以使用其他字符作为分隔符
    
  • awk:文本处理

    bash awk '/pattern/{print $0}' file.txt

编程语言

C/C++Python 等常用编程语言中均有库支持使用正则表达式进行便捷的字符串匹配。

搜索

常见的浏览器与 VSCode 等 IDE 的搜索功能均支持使用正则表达式进行搜索。

练习

  1. 使用 htop 命令查看系统资源及使用情况
  2. 新建文件夹并在该文件夹中使用 vim 编写 hello.c 并让其能够打印出 "hello,world"
  3. 使用 gcc 编译程序并成功运行(如果你不知道怎么编译可以考虑结合信息素养章节自行获取这部分的知识)
  4. 使用 shell 编写脚本 how_many_files.sh,使得可通过 bash how_many_files.sh <some path> 计算指定路径下有多少个文件(非递归)
  5. 使用 git 初始化这个仓库(拥有 hello.c 和 how_many_files.sh 两个文件)并推送到你的 GitHub 远程仓库上
  6. 使用 VSCode 打开这个文件夹,并使用其搜索的正则表达式功能尝试匹配所有文件中通过 #include 记号导入的库/文件(假设无注释)。例如下述文件中将捕获到 <cstdio>test.h 两个记号。

    #include <cstdio>
    #include "test.h"
    ...
    

推荐阅读

Missing semester

Linux 101(强烈推荐):中科大 Linux 俱乐部编写的 Linux 入门课程,涵盖了常见的 Linux 知识。