分类 技术 下的文章

GNU 调试器是一个发现程序缺陷的强大工具。

如果你是一个程序员,想在你的软件增加某些功能,你首先考虑实现它的方法:例如写一个方法、定义一个类,或者创建新的数据类型。然后你用编译器或解释器可以理解的编程语言来实现这个功能。但是,如果你觉得你所有代码都正确,但是编译器或解释器依然无法理解你的指令怎么办?如果软件大多数情况下都运行良好,但是在某些环境下出现缺陷怎么办?这种情况下,你得知道如何正确使用调试器找到问题的根源。

GNU 调试器 GNU Project Debugger GDB)是一个发现项目缺陷的强大工具。它通过追踪程序运行过程中发生了什么来帮助你发现程序错误或崩溃的原因。(LCTT 校注:GDB 全程是“GNU Project Debugger”,即 “GNU 项目调试器”,但是通常我们简称为“GNU 调试器”)

本文是 GDB 基本用法的实践教程。请跟随示例,打开命令行并克隆此仓库:

git clone https://github.com/hANSIc99/core_dump_example.git

快捷方式

GDB 的每条命令都可以缩短。例如:显示设定的断点的 info break 命令可以被缩短为 i break。你可能在其他地方看到过这种缩写,但在本文中,为了清晰展现使用的函数,我将所写出整个命令。

命令行参数

你可以将 GDB 附加到每个可执行文件。进入你克隆的仓库(core_dump_example),运行 make 进行编译。你现在能看到一个名为 coredump 的可执行文件。(更多信息,请参考我的文章《创建和调试 Linux 的转储文件》。)

要将 GDB 附加到这个可执行文件,请输入: gdb coredump

你的输出应如下所示:

gdb coredump output

返回结果显示没有找到调试符号。

调试信息是 目标文件 object file (可执行文件)的组成部分,调试信息包括数据类型、函数签名、源代码和操作码之间的关系。此时,你有两种选择:

  • 继续调试汇编代码(参见下文“无符号调试”)
  • 使用调试信息进行编译,参见下一节内容

使用调试信息进行编译

为了在二进制文件中包含调试信息,你必须重新编译。打开 Makefile,删除第 9 行的注释标签(#)后重新编译:

CFLAGS =-Wall -Werror -std=c++11 -g

-g 告诉编译器包含调试信息。运行 make clean,接着运行 make,然后再次调用 GDB。你得到如下输出后就可以调试代码了:

GDB output with symbols

新增的调试信息会增加可执行文件的大小。在这种情况下,执行文件增加了 2.5 倍(从 26,088 字节 增加到 65,480 字节)。

输入 run -c1,使用 -c1 开关启动程序。当程序运行到达 State_4 时将崩溃:

gdb output crash on c1 switch

你可以检索有关程序的其他信息,info source 命令提供了当前文件的信息:

gdb info source output

  • 101 行代码
  • 语言: C++
  • 编译器(版本、调优、架构、调试标志、语言标准)
  • 调试格式:DWARF 2
  • 没有预处理器宏指令(使用 GCC 编译时,宏仅在 使用 -g3 标志编译 时可用)。

info shared 命令打印了动态库列表机器在虚拟地址空间的地址,它们在启动时被加载到该地址,以便程序运行:

gdb info shared output

如果你想了解 Linux 中的库处理方式,请参见我的文章 在 Linux 中如何处理动态库和静态库

调试程序

你可能已经注意到,你可以在 GDB 中使用 run 命令启动程序。run 命令接受命令行参数,就像从控制台启动程序一样。-c1 开关会导致程序在第 4 阶段崩溃。要从头开始运行程序,你不用退出 GDB,只需再次运行 run 命令。如果没有 -c1 开关,程序将陷入死循环,你必须使用 Ctrl+C 来结束死循环。

gdb output stopped by sigint

你也可以一步一步运行程序。在 C/C++ 中,入口是 main 函数。使用 list main 命令打开显示 main 函数的部分源代码:

gdb output list main

main 函数在第 33 行,因此可以输入 break 33 在 33 行添加断点:

gdb output breakpoint added

输入 run 运行程序。正如预期的那样,程序在 main 函数处停止。输入 layout src 并排查看源代码:

gdb output break at main

你现在处于 GDB 的文本用户界面(TUI)模式。可以使用键盘向上和向下箭头键滚动查看源代码。

GDB 高亮显示当前执行行。你可以输入 nextn)命令逐行执行命令。如果你没有指定新的命令,GBD 会执行上一条命令。要逐行运行代码,只需按回车键。

有时,你会发现文本的输出有点显示不正常:

gdb output corrupted

如果发生这种情况,请按 Ctrl+L 重置屏幕。

使用 Ctrl+X+A 可以随时进入和退出 TUI 模式。你可以在手册中找到 其他的键绑定

要退出 GDB,只需输入 quit

设置监察点

这个示例程序的核心是一个在无限循环中运行的状态机。n_state 变量枚举了当前所有状态:

while(true){
        switch(n_state){
        case State_1:
                std::cout << "State_1 reached" << std::flush;
                n_state = State_2;
                break;
        case State_2:
                std::cout << "State_2 reached" << std::flush;
                n_state = State_3;
                break;
        
        (.....)
        
        }
}

如果你希望当 n_state 的值为 State_5 时停止程序。为此,请在 main 函数处停止程序并为 n_state 设置监察点:

watch n_state == State_5

只有当所需的变量在当前上下文中可用时,使用变量名设置监察点才有效。

当你输入 continue 继续运行程序时,你会得到如下输出:

gdb output stop on watchpoint_1

如果你继续运行程序,当监察点表达式评估为 false 时 GDB 将停止:

gdb output stop on watchpoint_2

你可以为一般的值变化、特定的值、读取或写入时来设置监察点。

更改断点和监察点

输入 info watchpoints 打印先前设置的监察点列表:

gdb output info watchpoints

删除断点和监察点

如你所见,监察点就是数字。要删除特定的监察点,请先输入 delete 后输入监察点的编号。例如,我的监察点编号为 2;要删除此监察点,输入 delete 2

注意: 如果你使用 delete 而没有指定数字,所有 监察点和断点将被删除。

这同样适用于断点。在下面的截屏中,我添加了几个断点,输入 info breakpoint 打印断点列表:

gdb output info breakpoints

要删除单个断点,请先输入 delete 后输入断点的编号。另外一种方式:你可以通过指定断点的行号来删除断点。例如,clear 78 命令将删除第 78 行设置的断点号 7。

禁用或启用断点和监察点

除了删除断点或监察点之外,你可以通过输入 disable,后输入编号禁用断点或监察点。在下文中,断点 3 和 4 被禁用,并在代码窗口中用减号标记:

disabled breakpoints

也可以通过输入类似 disable 2 - 4 修改某个范围内的断点或监察点。如果要重新激活这些点,请输入 enable,然后输入它们的编号。

条件断点

首先,输入 delete 删除所有断点和监察点。你仍然想使程序停在 main 函数处,如果你不想指定行号,可以通过直接指明该函数来添加断点。输入 break main 从而在 main 函数处添加断点。

输入 run 从头开始运行程序,程序将在 main 函数处停止。

main 函数包括变量 n_state_3_count,当状态机达到状态 3 时,该变量会递增。

基于 n_state_3_count 的值添加一个条件断点,请输入:

break 54 if n_state_3_count == 3

Set conditional breakpoint

继续运行程序。程序将在第 54 行停止之前运行状态机 3 次。要查看 n_state_3_count 的值,请输入:

print n_state_3_count

print variable

使断点成为条件断点

你也可以使现有断点成为条件断点。用 clear 54 命令删除最近添加的断点,并通过输入 break 54 命令添加一个简单的断点。你可以输入以下内容使此断点成为条件断点:

condition 3 n_state_3_count == 9

3 指的是断点编号。

modify breakpoint

在其他源文件中设置断点

如果你的程序由多个源文件组成,你可以在行号前指定文件名来设置断点,例如,break main. cpp:54

捕捉点

除了断点和监察点之外,你还可以设置捕获点。捕获点适用于执行系统调用、加载共享库或引发异常等事件。

要捕获用于写入 STDOUT 的 write 系统调用,请输入:

catch syscall write

catch syscall write output

每当程序写入控制台输出时,GDB 将中断执行。

在手册中,你可以找到一整章关于 断点、监察点和捕捉点 的内容。

评估和操作符号

print 命令可以打印变量的值。一般语法是 print <表达式> <值>。修改变量的值,请输入:

set variable <variable-name> <new-value>.

在下面的截屏中,我将变量 n_state_3_count 的值设为 123

catch syscall write output

/x 表达式以十六进制打印值;使用 & 运算符,你可以打印虚拟地址空间内的地址。

如果你不确定某个符号的数据类型,可以使用 whatis 来查明。

whatis output

如果你要列出 main 函数范围内可用的所有变量,请输入 info scope main :

info scope main output

DW_OP_fbreg 值是指基于当前子程序的堆栈偏移量。

或者,如果你已经在一个函数中并且想要列出当前堆栈帧上的所有变量,你可以使用 info locals :

info locals output

查看手册以了解更多 检查符号 的内容。

附加调试到一个正在运行的进程

gdb attach <进程 ID> 命令允许你通过指定进程 ID(PID)附加到一个已经在运行的进程进行调试。幸运的是,coredump 程序将其当前 PID 打印到屏幕上,因此你不必使用 pstop 手动查找 PID。

启动 coredump 应用程序的一个实例:

./coredump

coredump application

操作系统显示 PID 为 2849。打开一个单独的控制台窗口,移动到 coredump 应用程序的根目录,然后用 GDB 附加到该进程进行调试:

gdb attach 2849

attach GDB to coredump

当你用 GDB 附加到进程时,GDB 会立即停止进程运行。输入 layout srcbacktrace 来检查调用堆栈:

layout src and backtrace output

输出显示在 main.cpp 第 92 行调用 std::this_thread::sleep_for<...>(. ..) 函数时进程中断。

只要你退出 GDB,该进程将继续运行。

你可以在 GDB 手册中找到有关 附加调试正在运行的进程 的更多信息。

在堆栈中移动

在命令窗口,输入 up 两次可以在堆栈中向上移动到 main.cpp :

moving up the stack to main.cpp

通常,编译器将为每个函数或方法创建一个子程序。每个子程序都有自己的栈帧,所以在栈帧中向上移动意味着在调用栈中向上移动。

你可以在手册中找到有关 堆栈计算 的更多信息。

指定源文件

当调试一个已经在运行的进程时,GDB 将在当前工作目录中寻找源文件。你也可以使用 目录命令 手动指定源目录。

评估转储文件

阅读 创建和调试 Linux 的转储文件 了解有关此主题的信息。

参考文章太长,简单来说就是:

  1. 假设你使用的是最新版本的 Fedora
  2. 使用 -c1 开关调用 coredump:coredump -c1

Crash meme

  1. 使用 GDB 加载最新的转储文件:coredumpctl debug
  2. 打开 TUI 模式并输入 layout src

coredump output

backtrace 的输出显示崩溃发生在距离 main.cpp 五个栈帧之外。回车直接跳转到 main.cpp 中的错误代码行:

up 5 output

看源码发现程序试图释放一个内存管理函数没有返回的指针。这会导致未定义的行为并引起 SIGABRT

无符号调试

如果没有源代码,调试就会变得非常困难。当我在尝试解决逆向工程的挑战时,我第一次体验到了这一点。了解一些 汇编语言 的知识会很有用。

我们用例子看看它是如何运行的。

找到根目录,打开 Makefile,然后像下面一样编辑第 9 行:

CFLAGS =-Wall -Werror -std=c++11 #-g

要重新编译程序,先运行 make clean,再运行 make,最后启动 GDB。该程序不再有任何调试符号来引导源代码的走向。

no debugging symbols

info file 命令显示二进制文件的内存区域和入口点:

info file output

.text 区段始终从入口点开始,其中包含实际的操作码。要在入口点添加断点,输入 break *0x401110 然后输入 run 开始运行程序:

breakpoint at the entry point

要在某个地址设置断点,使用取消引用运算符 * 来指定地址。

选择反汇编程序风格

在深入研究汇编之前,你可以选择要使用的 汇编风格。 GDB 默认是 AT&T,但我更喜欢 Intel 语法。变更风格如下:

set disassembly-flavor intel

changing assembly flavor

现在输入 layout asm 调出汇编代码窗口,输入 layout reg 调出寄存器窗口。你现在应该看到如下输出:

layout asm and layout reg output

保存配置文件

尽管你已经输入了许多命令,但实际上还没有开始调试。如果你正在大量调试应用程序或尝试解决逆向工程的难题,则将 GDB 特定设置保存在文件中会很有用。

该项目的 GitHub 存储库中的 gdbinit 配置文件包含最近使用的命令:

set disassembly-flavor intel
set write on
break *0x401110
run -c2
layout asm
layout reg

set write on 命令使你能够在程序运行期间修改二进制文件。

退出 GDB 并使用配置文件重新启动 GDB : gdb -x gdbinit coredump

阅读指令

应用 c2 开关后,程序将崩溃。程序在入口函数处停止,因此你必须写入 continue 才能继续运行:

continuing execution after crash

idiv 指令进行整数除法运算:RAX 寄存器中为被除数,指定参数为除数。商被加载到 RAX 寄存器中,余数被加载到 RDX 中。

从寄存器角度,你可以看到 RAX 包含 5,因此你必须找出存储堆栈中位置为 rbp-0x4 的值。

读取内存

要读取原始内存内容,你必须指定比读取符号更多的参数。在汇编输出中向上滚动一点,可以看到堆栈的划分:

stack division output

你最感兴趣的应该是 rbp-0x4 的值,因为它是 idiv 的存储参数。你可以从截图中看到rbp-0x8 位置的下一个变量,所以 rbp-0x4 位置的变量是 4 字节宽。

在 GDB 中,你可以使用 x 命令查看任何内存内容:

x/ < 可选参数 nfu > < 内存地址 addr >

可选参数:

  • n:单元大小的重复计数(默认值:1)
  • f:格式说明符,如 printf
  • u:单元大小

    • b:字节
    • h:半字(2 个字节)
    • w: 字(4 个字节)(默认)
    • g: 双字(8 个字节)

要打印 rbp-0x4 的值,请输入 x/u $rbp-4 :

print value

如果你能记住这种模式,则可以直接查看内存。参见手册中的 查看内存 部分。

操作汇编

子程序 zeroDivide() 发生运算异常。当你用向上箭头键向上滚动一点时,你会找到下面信息:

0x401211 <_Z10zeroDividev>              push   rbp
0x401212 <_Z10zeroDividev+1>            mov    rbp,rsp

这被称为 函数前言

  1. 调用函数的基指针(rbp)存放在栈上
  2. 栈指针(rsp)的值被加载到基指针(rbp

完全跳过这个子程序。你可以使用 backtrace 查看调用堆栈。在 main 函数之前只有一个堆栈帧,所以你可以用一次 up 回到 main :

Callstack assembly

在你的 main 函数中,你会找到下面信息:

0x401431 <main+497>     cmp    BYTE PTR [rbp-0x12],0x0
0x401435 <main+501>     je     0x40145f <main+543>
0x401437 <main+503>     call   0x401211<_Z10zeroDividev>

子程序 zeroDivide() 仅在 jump equal (je)true 时进入。你可以轻松地将其替换为 jump-not-equal (jne) 指令,该指令的操作码为 0x75(假设你使用的是 x86/64 架构;其他架构上的操作码不同)。输入 run 重新启动程序。当程序在入口函数处停止时,设置操作码:

set *(unsigned char*)0x401435 = 0x75

最后,输入 continue 。该程序将跳过子程序 zeroDivide() 并且不会再崩溃。

总结

你会在许多集成开发环境(IDE)中发现 GDB 运行在后台,包括 Qt Creator 和 VSCodium 的 本地调试 扩展。

GDB in VSCodium

了解如何充分利用 GDB 的功能很有用。一般情况下,并非所有 GDB 的功能都可以在 IDE 中使用,因此你可以从命令行使用 GDB 的经验中受益。


via: https://opensource.com/article/21/1/gnu-project-debugger

作者:Stephan Avenwedde 选题:lkxed 译者:Maisie-x 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

本初学者指南解释了如何在 Ubuntu/Linux 中快速共享一个文件夹。

在 Ubuntu/Linux 中共享一个文件夹并在其他操作系统(如 Windows)中通过网络访问并不难。默认情况下,Ubuntu 并没有安装所需的软件包。但是,你可以打开安装向导来自动安装所需的软件。

指南 适用于所有 Ubuntu 版本(包括 22.04、20.04、18.04、19.10 以及即将发布的版本 —— 除非此功能的设计发生重大的变化)。

Ubuntu 中共享文件夹的步骤

步骤 1: 打开文件管理器,右键单击共享的文件夹。点击上下文菜单中的“本地网络共享”选项。

本地网络共享选项

步骤 2: 在文件夹共享对话框中点击共享文件夹复选框。

这将在你的系统中安装 Samba) 软件包。Samba 用于在 Windows 和 Unix 系统之间通过网络共享文件和打印机。

文件夹共享选项 - 安装 Samba

步骤 3: 安装 Samba 后,执行以下操作共享文件夹或目录。

  • 选中共享文件夹复选框。
  • 输入共享名称。这将是你从另一个系统(如 Windows)看到的名称。尽量不要使用任何带有空格的名称。
  • (可选)通过勾选相应选项,你可以控制共享文件夹的写入权限,以及允许访客访问。
  • 如果你允许访客访问,则没有凭据的人可以访问共享文件夹。所以要谨慎。
  • 如果你希望用户输入用户名和密码,打开终端并运行以下命令。
sudo smbpasswd -a 用户名

用户名 应该是对应 Ubuntu 系统的有效用户。

现在,你应该已经设置好了共享的文件夹或目录。

如何访问共享文件夹

从 Ubuntu/Linux 系统中访问共享文件夹,你需要系统的 IP 地址或主机名。为此,打开“ 系统设置 System Settings -> Wi-Fi -> 获取 IP 地址 Get the IP address ”。

IP 地址设置

如果你运行的是 Linux 发行版不是 Ubuntu,此步骤略有不同。你可能想运行 ip addr 来获取 IP 地址,如下所示:

在 Linux 中查找 IP 地址

一旦你获得 IP 地址,就可以在 Ubuntu/Linux 系统中打开文件管理器,然后在地址栏中输入以下内容。注意:你应该修改为你系统的 IP 地址。

你现在可以看到共享文件夹上面显示了一个小共享图标,表示网络共享文件夹。

共享文件夹

要在 Windows 系统 访问共享文件夹,打开运行(按下 Windows + R)或打开资源管理器,输入以下地址。注意:你应该修改为你系统的 IP 地址和文件夹名称。

\\192.168.43.19\Folder

你应该能够查看共享文件夹的内容,并根据授予的权限修改它。

总结

我已经向你展示了如何从 Ubuntu 共享一个件夹,并通过 IP 地址在 Windows 系统中访问。对于其他 Linux 发行版,你也可以执行相同的步骤。如果本文对你有帮助,在下面的评论框中告诉我。


via: https://www.debugpoint.com/guide-how-share-folder-between-ubuntu-linux-windows/

作者:Arindam 选题:lkxed 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

面向初学者的 Docker 基本命令指南。

这篇详细的 Docker 教程覆盖了核心的 Docker 命令,比如,如何创建新容器、运行容器、删除容器等。另外,这篇教程也解释了如何从已有的容器构建你自己的 Docker 镜像,如何移除容器和镜像。言归正传,现在开始 Docker 的基本用法。

Docker 安装步骤

大多数现代 Linux 操作系统都可以安装 Docker。如果还没安装过 Docker,请参考下面的步骤:

什么是 Docker 镜像和 Docker 容器?

在开始 Docker 之前,我先说明一下 Docker 镜像和 Docker 容器是什么。

Docker 镜像是一个描述容器如何运行的的文件,Docker 容器是 Docker 镜像在运行或被终止时的一个阶段。

容器和主机上的其他文件是隔离的。

当我们运行一个 Docker 容器的时候,它会使用一个被隔离出来的文件系统,这个文件系统是由一个 Docker 镜像提供的。Docker 镜像包含了运行应用程序所需要的一切东西 - 所有的依赖、配置、脚本、二进制文件等等。

镜像也包含容器所需要的其他配置项,比如说环境变量、默认运行的命令,以及其他元数据。

Linux 下的 Docker 入门

下面的所有步骤都已在 Ubuntu 22.04、20.04 以及 18.04 LTS 服务器版本中测试通过。后续小节中提供的步骤对于所有 Linux 平台都是通用的。比如,在基于 RHEL 的系统中(比如 AlmaLinux)可以运行相同的命令。

1、搜索 Docker 镜像

我们可以从叫做 Docker hub 的 Docker 官方库获得镜像,或者我们也可以制作自己的镜像。

有些人可能不清楚,Docker hub 是一个线上的中心化仓库,Docker 用户们在上面构建、测试、然后保存他们的 Docker 镜像。Docker hub 有数以万计的 Docker 镜像,而且这个数字还在每天增长。

你可以从命令行通过 `docker search 命令搜索任意 Docker 镜像。

比如要搜索基于 Alpine Linux 的 Docker 镜像,运行:

$ sudo docker search alpine

输出结果:

Search Docker Images

搜索基于 Ubuntu 的镜像,运行:

$ sudo docker search ubuntu

你还可以搜索其他任意的应用,比如 Nginx,像下面这样:

$ sudo docker search nginx

Docker hub 有各种各样的镜像。你能在 Docker hub 上找到各种已构建好的 Docker 镜像,比如说操作系统、应用,或者多个应用的合体(比如 LAMP 栈)。

如果你找的东西不在上面,你还可以构建一个镜像,然后通过 Docker hub 向其他人开放,或者只是自己用。

2、下载 Docker 镜像

从终端运行下面的命令可以下载 Ubuntu OS 的 Docker 镜像:

$ sudo docker pull ubuntu

上面的这个命令会从 Docker hub 下载最新的 Ubuntu 镜像。

输出结果:

Using default tag: latest
latest: Pulling from library/ubuntu
405f018f9d1d: Pull complete
Digest: sha256:b6b83d3c331794420340093eb706a6f152d9c1fa51b262d9bf34594887c2c7ac
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

你也可以用下面的命令下载指定版本的 Ubuntu 镜像:

$ sudo docker pull ubuntu:20.04

Docker 允许我们下载任何镜像,并且在那个镜像上创建容器,这些操作与主机的操作系统无关。

比如要下载 Alpine 系统的镜像,运行:

$ sudo docker pull alpine

Download Docker Images

3、列出 Docker 镜像

所有已下载的 Docker 镜像都保存在 /var/lib/docker 路径下。

要查看所有已下载的 Docker 镜像,运行:

$ sudo docker images

输出结果:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ubuntu       latest    27941809078c   3 weeks ago   77.8MB
ubuntu       20.04     20fffa419e3a   3 weeks ago   72.8MB
alpine       latest    e66264b98777   5 weeks ago   5.52MB

List Docker Images

从上面可以看出来,我已经下载了三个 Docker 镜像 - Ubuntu latest、Ubuntu 20.04 和 Alpine Linux。

现在,我们看一下接下来如何从下载的镜像启动或者运行容器。

4、运行 Docker 容器

有两种方法我们可以启动一个容器 - 使用 Docker 镜像的 标签 TAG 或者 镜像 ID Image ID

标签指的是一个特定的镜像快照, 镜像 ID Image ID 是那个镜像对应的唯一识别码。

可以查看下面这个截图:

Docker Image Tag and ID

从上面的解脱可以看到,标签是 latest20.04

  • 27941809078c 是 Ubuntu latest 的 Docker 镜像的镜像 ID,
  • 20fffa419e3a 是 Ubuntu 20.04 的 Docker 镜像的镜像 ID,
  • e66264b98777 是 Alpine latest 的 Docker 镜像的镜像 ID。
4.1、使用标签运行容器

下载选择好的 Docker 镜像后,运行下面的命令来启动 Docker 容器,并且通过它的标签进行连接。

$ sudo docker run -t -i ubuntu:latest /bin/bash

或者,

$ sudo docker run -it ubuntu:latest /bin/bash

这里,

  • -t:在 Ubuntu 容器内分配一个伪终端。
  • -i:通过从容器获取一个标准输入(STDIN),允许我们创建一个可交互的连接。
  • ubuntu:latest:标签为 latest 的 Ubuntu Docker 镜像。
  • /bin/bash:新容器的 BASH shell。这个是可选项。如果你不加 shell 的话,会分配默认的 shell 给容器。

启动容器后,会自动进入容器的 shell(命令行):

Run Containers Using Tag

基于最新 Ubuntu 镜像的容器现在已经启动了。所有的新容器都会被赋予一个名字和唯一的 ID。从上面的输出可以看到,那个 Ubuntu 容器的 ID 是 2f2a5b826762。一会儿我们会看到从哪找到容器的名字。

现在就可以在容器里面工作了。当你完成容器内的工作后,你可以回到主机操作系统的终端(在我这个例子中,操作系统是 Ubuntu 22.04 LTS)而不需要关掉容器(客户机)。

4.2、从运行中的容器中脱离

使用 CTRL+P 然后 CTRL+Q 就可以从运行中的容器脱离(不需要关闭)。

现在,你就回到了你原来的主机的终端窗口。请注意,容器还在后台运行中,我们并没有关掉它。

4.3、使用镜像 ID 运行容器

另一种启动容器并且连接进去的方式是通过使用镜像 ID,像下面这样:

$ sudo docker run -it 20fffa419e3a /bin/bash

这里,

  • 20fffa419e3a - 镜像 ID

CTRL+P 然后 CTRL+Q 可以从当前容器中脱离回到主机系统的终端。我们只是从容器中脱离,但是没有让它停止。容器仍然在后台运行中。

4.4. 在脱离模式中运行容器

在前面的小结中,我们启动了一个容器并且立刻连接了进去。然后当容器中的工作结束后,我们从容器中脱离了出来。

你也可以在脱离模式(不需要自动连接进去)中启动容器。

在后台运行一个容器,输入命令:

$ sudo docker run -it -d alpine:latest

输出结果:

d74f2ceb5f3ad2dbddb0b26e372adb14efff91e75e7763418dbd12d1d227129d

上面输出结果的前 12 字符代表的是容器的 ID。

通过 docker ps 命令,你可以验证容器是否在运行:

$ sudo docker ps
CONTAINER ID   IMAGE           COMMAND     CREATED         STATUS         PORTS     NAMES
d74f2ceb5f3a   alpine:latest   "/bin/sh"   3 seconds ago   Up 2 seconds             zen_pascal

Run Containers In Background

从上面个的输出结果中可以看到,我们创建了一个 Alpine 容器,但是还没有连接进去。

如果你想连接进去,很简单,运行:

$ sudo docker attach d74f2ceb5f3a

5、查看运行中的容器

查看运行中的容器,运行下面的命令:

$ sudo docker ps

输出结果:

CONTAINER ID   IMAGE           COMMAND       CREATED          STATUS          PORTS     NAMES
f7e04eed577e   20fffa419e3a    "/bin/bash"   6 minutes ago    Up 6 minutes              brave_mclean
2f2a5b826762   ubuntu:latest   "/bin/bash"   18 minutes ago   Up 18 minutes             hungry_leavitt

View Running Containers

这里,

  • f7e04eed577e 是由镜像 2f2a5b826762 创建的 Ubuntu 容器的 ID。并且,brave_mclean 是这个容器的名字。
  • 2f2a5b826762 是由镜像 “ubuntu:latest” 创建的 Ubuntu 容器的 ID。并且,hungry_leavitt 是这个容器的名字。

当一个新容器被创建后,会赋给它一个唯一的 ID 和名字,这样我们就能通过它的 ID 和名字来连接它。

注意:请注意容器 ID 和 Docker 镜像 ID 是不同的

列出所有可用的(运行或者停止)容器,运行:

$ sudo docker ps -a

6、从运行中的容器脱离或连接

首先,通过 docker ps 命令找到容器的 ID。

$ sudo docker ps

然后,运行 docker attach 命令连接到运行中的容器。

$ sudo docker attach <container-id>

比如像下面这样,我要连接到 ID 为 f7e04eed577e 的容器:

$ sudo docker attach f7e04eed577e

你也可以通过使用它的名字连接到一个容器。

$ sudo docker attach brave_mclean

现在你就登录到这个容器了。

想要从容器脱离,只要按 CTRL+P 然后 CTRL+Q

7、启动、重启、暂停和终止容器

你可以使用容器的名字或 ID 来启动,重启,暂停或者终止一个 Docker 容器。

首先,通过 docker ps -a 命令找到容器的名字或 ID。

Find Container ID And Name

现在,通过使用 docker start 命令,加上名字或 ID,你可以启动一个容器,像下面这样:

$ sudo docker start modest_cray
$ sudo docker start 10615254bb45

用空格隔开,就可以启动多个容器,像下面这样:

$ sudo docker start 24b5ee8c3d3a 56faac6d20ad d74f2ceb5f3a

优雅的重启一个运行中的容器,运行:

$ sudo docker start 10615254bb45

暂停一个运行中的容器:

$ sudo docker pause 10615254bb45

把暂停的容器恢复过来:

$ sudo docker unpause 10615254bb45

直到其它容器都停止前,阻塞一个容器:

$ sudo docker wait 10615254bb45

我们可以很容易地通过使用它的名字或 ID 来终止一个容器。如果你已经在容器的 shell 里了,只需要运行下面的命令就可以非常简单的终止:

# exit

你也可以使用下面的命令从 Docker 的主机系统中终止(关闭容器)容器:

$ sudo docker stop 10615254bb45

用空格隔开,你可以退出多个容器,像下面这样。

$ sudo docker stop 35b5ee8c3d3a 10615254bb45

在退出容器之后,通过列出所有容器的命令来确保它确实被终止了:

$ sudo docker ps

8、强行关闭 Docker 容器

docker stop 命令可以非常优雅的关掉运行中的容器。有时候,你可能卡在一个没有响应的容器,或者你想强制关掉容器。

通过给一个运行中的容器发送 SIGKILL 来强行关闭容器,运行:

$ sudo docker kill 10615254bb45

9、在关闭容器后自动删除他们

也许你想测试一个容器,然后当你完成在容器中的工作就把它删掉。如果是这样,通过使用 --rm 标签在关闭后自动删掉容器:

$ sudo docker run -it --rm debian:latest

当你从容器中退出,它会自动被删掉。

Automatically Delete Containers

从上面的结果可以看到,我先创建了一个新的 Debian 容器。当我退出这个容器的时候,它就被自动删掉了。docker ps -a 命令的输出结果显示,Debian 容器现在不存在。

10、给容器命名

如果你再看一下之前命令的输出结果,当你启动一个容器的时候,每个容器都被赋予了一个随机的名字。如果你不命名你的容器,Docker 会自动替你给他们命名。

现在看一下下面的例子:

$ sudo docker run -it -d alpine:latest
2af79e97a825c91bf374b4862b9e7c22fc22acd1598005e8bea3439805ec335d
$ sudo docker run -it -d alpine:latest
80b53b7e661d33696b65c78267fc3f067b6100799c925910db4721963e3fae0a
$ sudo docker ps
CONTAINER ID   IMAGE           COMMAND     CREATED         STATUS         PORTS     NAMES
80b53b7e661d   alpine:latest   "/bin/sh"   3 seconds ago   Up 2 seconds             bold_margulis
2af79e97a825   alpine:latest   "/bin/sh"   6 seconds ago   Up 5 seconds             recursing_taussig

从上面的结果可以看到,尽管我用同一个 Docker 镜像创建了两个容器,它们获得了不同的 ID 和名字。

如果你想给容器赋一个不变的名字,使用 --name 标签,像下面这样:

$ sudo docker run -it -d --name ostechnix_alpine alpine:latest

上面的命令会在脱离模式中创建一个叫做 ostechnix_alpine 的新容器。

我们看一下当前运行的容器列表:

$ sudo docker ps

输出结果:

CONTAINER ID   IMAGE           COMMAND     CREATED         STATUS         PORTS     NAMES
397111fac537   alpine:latest   "/bin/sh"   2 seconds ago   Up 2 seconds             ostechnix_alpine
80b53b7e661d   alpine:latest   "/bin/sh"   7 minutes ago   Up 7 minutes             bold_margulis
2af79e97a825   alpine:latest   "/bin/sh"   7 minutes ago   Up 7 minutes             recursing_taussig

Assign Name To Containers

注意到上面输出结果中的第一个容器的名字了吗?对了,我们给这个容器分配了一个自定义的名字(也就是 ostechnix_alpine)。

给容器分配自定义的名字可以给我们带来其他好处。只要看一下容器的名字,我们就能很容易的确定那个容器里面安装了什么。

11、构建自定义 Docker 镜像

Docker 不仅仅是下载和使用已存在的容器。你也可以创建自己的自定义 Docker 镜像。

现在我们开始一个 Ubuntu 容器:

$ sudo docker run -it ubuntu:latest

现在,你会进入到容器的 shell。

然后,在容器中,你可以安装任何的软件或者做你想做的事情。

比如,我们在容器中安装 Apache Web 服务器。

# apt update
# apt install apache2

相似地,在容器中,可以根据自己的需要安装和测试软件。

完成以后,从容器脱离(不要退出)回到主机系统的 shell。不要终止或者关闭容器。使用 CTRL+P 然后 CTRL+Q 从容器中脱离,这样不会关闭容器。

在你的 Docker 主机的终端,运行下面的命令来找到容器 ID:

$ sudo docker ps

最后,创建一个当前运行中的容器的 Docker 镜像,使用命令:

$ sudo docker commit 377e6d77ebb5 ostechnix/ubuntu_apache

输出结果:

sha256:bc5e5f95ca592a3585fda2c5a40ec30c98e292046ef70390a2c3b7863cc6f7c1

这里,

  • 377e6d77ebb5 – Ubuntu 容器的 ID。
  • ostechnix – 创建容器的用户的名字。
  • ubuntu_apache – 用户 ostechnix 创建的 Docker 镜像的名字。

现在我们查看一下新的 Docker 镜像是否被创建了,使用下面的命令:

$ sudo docker images

输出结果:

ostechnix/ubuntu_apache

Build Custom Docker Images

从上面给的结果中可以看到,从运行中的容器创建的新 Docker 镜像已经在我们的 Docker 主机系统中了。

现在你就可以从这个新的 Docker 镜像创建行容器了,用之前的命令:

$ sudo docker run -it ostechnix/ubuntu_apache

12、移除容器

当你在 Docker 容器中完成所有开发后,如果你不需要它们了,你可以删掉它们。

为此,首先我们需要终止(关闭)运行中的容器。

用这个命令来看一下运行中的容器:

$ sudo docker ps

输出结果:

CONTAINER ID   IMAGE           COMMAND   CREATED         STATUS         PORTS     NAMES
377e6d77ebb5   ubuntu:latest   "bash"    7 minutes ago   Up 7 minutes             elegant_beaver

通过使用它的 ID 来终止运行中的容器:

$ sudo docker stop 377e6d77ebb5

现在,使用这个命令删除容器:

$ sudo docker rm 377e6d77ebb5

同样,如果不再需要所有的容器,关闭并删除它们。

一个一个的删除多个容器会是一项繁琐的工作。所以,我们可以把所有停止的容器一次性删掉,运行:

$ sudo docker container prune

Y 然后回车键,这些容器就被删掉了。

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
397111fac5374921b974721ee646b2d5fbae61ca9c6e8b90fbf47952f382a46b
80b53b7e661d33696b65c78267fc3f067b6100799c925910db4721963e3fae0a
[...]
Total reclaimed space: 176B

Delete Containers

这个命令只有在最新版中有效。

使用下面的命令来验证是否所有容器都被删除了:

$ sudo docker ps -a

如果看不到任何结果,说明所有容器被删掉了。

13、删除 Docker 镜像

记住,在删除所有镜像之前,首先要删掉所有从那些镜像创建的容器。

当你删掉容器后,你可以删掉你不需要的 Docker 镜像。

列出所有下载的 Docker 镜像:

$ sudo docker images

输出结果:

REPOSITORY                TAG       IMAGE ID       CREATED          SIZE
ostechnix/ubuntu_apache   latest    bc5e5f95ca59   14 minutes ago   229MB
debian                    latest    d2780094a226   11 days ago      124MB
ubuntu                    latest    27941809078c   3 weeks ago      77.8MB
ubuntu                    20.04     20fffa419e3a   3 weeks ago      72.8MB
alpine                    latest    e66264b98777   5 weeks ago      5.52MB

从上面可以看到,在我们的主机上有 5 个 Docker 镜像。

通过使用镜像 ID 来删掉它们:

$ sudo docker rmi ce5aa74a48f1

输出结果:

Untagged: ostechnix/ubuntu_apache:latest
Deleted: sha256:bc5e5f95ca592a3585fda2c5a40ec30c98e292046ef70390a2c3b7863cc6f7c1
Deleted: sha256:a8e4797160a2b2d33d8bd1bd67e008260c022b3a53fbcc198b2b74d9eae5961d

同样,删除其他所有 Docker 镜像。

删掉所有未运行的容器、所有镜像、构建的缓存、所有网络,运行:

$ sudo docker system prune -a

使用这个命令的时候要注意,它会删掉所有没有使用的容器、网络、镜像(包括 挂起 dangling 未使用 unreferenced 的)

Delete Everything In Docker

默认情况下,即使当前没有容器在使用 磁盘卷 volumes ,为防止重要数据被删除,磁盘卷也不会被删除。

如果你想删掉所有东西,包括分配的卷,使用 --volumes 标签。

$ sudo docker system prune -a --volumes

Docker 问题汇总

如果 Docker 镜像正在被运行或停止的容器使用,Docker 不会允许你删除这些镜像。

比如,当我尝试从一个以前的 Ubuntu 服务器上删除 ID 为 b72889fa879c 的 Docker 镜像。我会得到下面的错误:

Error response from daemon: conflict: unable to delete b72889fa879c (must be forced) - image is being used by stopped container dde4dd285377

这是因为你想删除的 Docker 镜像正在被另一个容器使用。

所以,我们先查看一下运行中的容器,使用命令:

$ sudo docker ps

输出结果:

Show running docker containers

噢,没有运行中的容器。

我们在看一下所有的容器(运行和停止的),用这个命令:

$ sudo docker ps -a

输出结果:

Show running and stopped docker containers

可以看到,仍然有停止的容器在使用其中一个 Docker 镜像。所以,我们先把所有容器删掉。

比如:

$ sudo docker rm 12e892156219

类似地,向上面那样,用对应容器的 ID 将它们都删除。

当把所有容器删掉后,移除掉 Docker 镜像。

比如:

$ sudo docker rmi b72889fa879c

就这么简单。现在确认是否还有其他 Docker 镜像在主机上,使用命令:

$ sudo docker images

你现在应该不再有任何 docker 镜像了。

总结

在这篇全面的 Docker 入门教程中,我们解释了 Docker 的基本操作,比如创建、运行、搜索、删除容器,还有从 Docker 镜像构建你自己的容器。同时,我们也解释了如何在不需要 Docker 容器和镜像的时候删除它们。

希望你现在对 Docker 的使用 有一个基本的了解。

更多细节,请参考这篇教程最下面的官方资源链接,或者在下面的评论区进行评论。

相关资料


via: https://ostechnix.com/getting-started-with-docker/

作者:sk 选题:lkxed 译者:MCGA 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

FreeDOS 提供了一个叫做 FreeDOS Edit 的用户友好的文本编辑器。

 title=

在任何操作系统中,编辑文件都是一项常有的任务。当你想去做一个某事的笔记、写封信给朋友或升级一个系统配置 —— 你需要一个文本编辑器。FreeDOS 提供了一个用户友好的文本编辑器(也许没啥想象力)叫做 “FreeDOS Edit”。

编辑文件

最简单的启用 FreeDOS Edit 的方式就就是输入 EDIT。它提供一个空的编辑器窗口。图案背景显示为一个空的“桌面”——提醒你没有编辑任何文件。

 title=

就像多数 DOS 应用程序一样,你可以按下你键盘上的 Alt 键来访问 Edit 的菜单。这就激活了这个菜单。在你按下 Alt 后,Edit 将切换到“菜单”访问方式,并高亮 “ 文件 File ” 菜单。如果你想要访问菜单栏上的一个不同的菜单,可以使用左右方向键。按向下的方向键并按下回车键来“进入”菜单。

 title=

你注意到所有菜单标题的第一个字母是不同的颜色么?这种高亮字母显示了一种快捷方式。例如,“ 文件 File ”菜单的“F”高亮为红色。所以你可以按下 Alt+FAltF 同时按下),Edit 会显示“ 文件 File ”菜单。

 title=

你可以使用“ 文件 File ”菜单来开始一个新的(空)文件,或打开一个存在的文件。让我们开始一个新文件,使用方向键移动到“ 新建 New “然后按下回车键。你也可以用 Ctrl+NCtrlN 同时按下)打开一个新文件。

 title=

此后,编辑文件应该非常简单。大多数熟悉的快捷键都可以在 FreeDOS Edit 中使用:Ctrl+C 复制文本,Ctrl+X 剪贴文本,和 Ctrl+V 将复制的或剪贴的文本粘贴到新的地方。如果你需要在一个长文档中寻找一个特殊文本,按下 Ctrl+F。保存你的工作成果,请使用 Ctrl+S 以将变更提交到硬盘。

在 Edit 中编程

如果你是个程序员,你也许会发现扩展的 ASCII 表是一个有用的工具。DOS 系统支持“拓展的” ASCII字符集,通常被称之为“代码页 437”。0 到 127 的标准字符包括字母 A 到 Z(大写和小写)、数字和特殊字符,如标点符号。但是,从 128 到 255 的 DOS 拓展字符包括其它语言字符和“画线”元素。DOS 程序员有时需要使用这些拓展 ASCII 字符,所以 FreeDOS Edit 可以很容易地查看所有 ASCII 码和它们的相关字符的表格。

要查看这个 ASCII 表,请使用“ 工具 Utilities ”菜单,选择“ ASCII 表 ASCII Table ”菜单项,这将显示一个包含该表格的窗口。

 title=

沿着左边,这张表显示十六进制值“00”到“F0”,顶部展示了单一值“0”到“F”。这些为每个字符的十六进制代码提供了一个快速参考。例如,第一行(00)和第一列(0)中的项目具有十六进制值 00 + 0,即0x00(“NULL”值)。而第五行(40)和第二列(1)中的字符,其数值为 40 + 1,即 0x41(字母 “A”)。

 title=

当你在表格内移动光标高亮不同的字符时,你会看到表格底部的值发生变化,展示了字符的十进制、十六进制和八进制编码。例如,移动光标以高亮在 C0 行和第 5 列的“行交叉”字符,显示这个扩展字符的代码为 197(十进制)、0xc5(十六进制)和 305(八进制)。在一个程序中,你可以通过输入十六进制值 0xc5 或八进制“转义代码” \305 来引用这个扩展字符。

“行交叉”字符是 197(十进制)、0xc5(十六进制)和 305(八进制)

请随意浏览 Edit 中的菜单,以发现其他不错的功能。例如,“ 选项 Options ”菜单允许你更改 Edit 的行为和外观。如果你喜欢使用更密集的显示,可以使用“ 显示 Display ”菜单(在“ 选项 Options ”下)将 Edit 设置为 25、43 或 50 行。你还可以强制 Edit 以单色(黑底白字)或反转模式(白底黑字)显示。

(文内图片来自 Jim Hall,CC-BY SA 4.0)


via: https://opensource.com/article/21/6/freedos-text-editor

作者:Jim Hall 选题:lujun9972 译者:yjacks 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这个初学者指南解释了在 Arch Linux 中安装 Yay AUR 助手的步骤。

Yay 是 “Yet Another Yogurt” 的缩写(LCTT 校注:Yogurt 是另外一个已经停止维护的 AUR 助手)。从技术上讲,它是用 Go 编程语言 编写的 pacman 封装器和 AUR 助手。它是当今最流行的 Arch 用户仓库(AUR) 助手。使用 Yay,你可以利用庞大的 Arch 用户软件包库并轻松编译和安装任何软件。

它可以自动执行许多包管理任务,例如搜索、动态解决依赖关系、编译和构建包,当然还有在 AUR 发布包。

让我们看看如何在 Arch Linux 或任何基于 Arch 的发行版(如 Manjaro)中安装 Yay。安装 Arch Linux 后,你可以通过 pacman 包管理器从三个主要的 Arch 官方仓库安装包。但是在全新的 Arch Linux 安装后,默认情况下不会安装 Yay。因此,你需要手动安装它以利用 AUR。

本指南涵盖以下主题:

  • 在 Arch Linux 中安装 Yay
  • 在 Manjaro 中安装 Yay
  • 如何在 Arch Linux 和 Manjaro 中使用 Yay 安装包
  • 一些 Yay 的技巧

在 Arch Linux 中安装 Yay

先决条件

打开终端并运行以下命令。出现提示时提供管理员密码。这些步骤需要 base-devel 包和 git 包进行编译和安装。

sudo pacman -S base-devel
sudo pacman -S git

Install git

安装 Yay

yay 包在 Arch 仓库中有两个版本,如下所示。

对于本指南,我使用了稳定版。现在,进入 /opt 目录并克隆 git 仓库。

cd /opt
sudo git clone https://aur.archlinux.org/yay.git

clone the yay repo

更改源目录的所有者。将 debugpoint 替换为你的用户名。

sudo chown -R debugpoint:users ./yay

如果你不知道用户或组,可以使用以下示例查找用户和组。

id debugpoint

进入目录并编译。

cd yay
makepkg -si

这样就完成了 Arch Linux 中 Yay 的安装。

Install yay in Arch Linux

在 Manjaro 中安装 Yay

如果你使用 Manjaro Linux,yay 包可以在社区仓库中找到。你可以在 Manjaro 中使用以下命令轻松安装。

pacman -Syyu  
pacman -S yay

现在,让我们看看如何使用 Yay 安装任何软件包,以及一些基本的 yay 用法。

如何使用 Yay 安装包

首先在 AUR 网站上搜索安装任何应用以获取包名。例如,要安装 featherpad 文本编辑器,请运行以下命令。

yay -S featherpad

安装后,你可以在应用菜单中找到应用启动器。

Install a sample application (featherpad) using yay

一些 Yay 的技巧

你还可以使用 yay 进行许多调整和系统操作。下面是一些示例。

刷新系统包并升级

yay -Syu

使用包的开发版本并升级(运行此命令时要小心)

yay -Syu --devel --timeupdate

删除任何包(例如,featherpad)

yay -Rns featherpad

快速获取系统统计信息

system stat using yay

yay -Ps

我希望这个初学者指南能帮助你在 Arch Linux 中安装 Yay,然后使用 Yay 安装包,并执行不同的系统操作。


via: https://www.debugpoint.com/install-yay-arch/

作者:Arindam 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这是一个可能的情景。你的系统收到了内核更新,但不知何故,事情不像以前那样顺利。

你意识到,如果你启动到较旧的内核(是的,你可以降级内核),一切都会恢复正常。

高兴之余你会觉得有点儿不爽。因为你不得不在每次启动时手动选择较旧的内核。

一位年长的读者遇到了这个问题。Linux Mint 中的新内核更新没有按预期工作。启动到较旧的内核“修复”了问题,但麻烦的是在每次启动时要去手动选择较旧的内核。

删除新内核而使用旧内核不是一个好主意,因为新内核将会在下一次系统更新时被安装使用。

因此,我建议设置成默认启动到较旧的 Linux 内核。怎么做?这就是我将在本教程中向你展示的内容。

启动至较旧的 Linux 内核

你可能不了解,你的 Linux 发行版会在你的系统上安装多个 Linux 内核。不信?使用以下命令 列出 Ubuntu 中已安装的内核

apt list --installed | grep linux-image

当你升级系统时会获得一个新版本的内核,这时你的系统会自动选择启动至最新的可用内核。

grub 屏幕中,你可以转到 高级选项 Advanced option (较旧的 Linux 版本):

ubuntu grub

在这里,你可以看到要启动的可用内核。选择较旧的(不带 恢复选项 recovery option 的条目):

grub 高级选项

你不会注意到任何显示的差异。你的文件和应用程序保持不变。

现在你已经启动到旧内核,是时候让你的系统自动启动到它了。

使旧内核成为默认启动项

如果你乐于使用 Linux 终端和命令,你可以修改 /etc/default/grub 文件并在其中添加以下行:

GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true

然后使用如下命令 更新 GRUB

sudo update-grub

你在这里所做的是告诉你的系统将当前使用的启动项保存为将来运行 GRUB 的默认启动项。

然而,并不是每个人都善于使用命令行,因此我将专注于一个名为 Grub Customizer 的 GUI 工具。

安装 Grub Customizer

使用官方 PPA 在基于 Ubuntu 的发行版中安装 Grub Customizer

sudo add-apt-repository ppa:danielrichter2007/grub-customizer
sudo apt update
sudo apt install grub-customizer

对于其他发行版,请使用你的包管理器来安装此工具。

使用 Grub Customizer 更改默认启动项

当你运行 Grub Customizer 时,它会显示可用的启动项。

ubuntu 的 grub customizer

在这里你有两个选择。

选择一: 选择所需的内核项并使用箭头按钮(显示在顶部菜单上)将其向上移动。

在 Ubuntu grub 将旧内核向上移动

选择二: 先前的启动项 previously booted entry 设为 默认启动项 default entry

将当前启动项设为默认 Ubuntu 启动项

我建议使用第二个选择,因为即使有新的内核更新它也可以工作。

这样你就可以在 Ubuntu 或其他发行版中降级内核,甚至无需删除新内核版本。

请注意,像 Ubuntu 这样的发行版大部分一次只保留两个内核版本。因此,最终你首选的旧内核将在新的内核版本释出时被删除。

这个巧妙的技巧曾助我脱困。当时我 在 Ubuntu 中安装最新的 Linux 内核 ,由于某种原因它与我的音频系统有些兼容问题。

无论是什么原因,你现在都知道如何自动启动到旧内核。

如果有问题或建议,请在评论区留言。


via: https://itsfoss.com/boot-older-kernel-default/

作者:Abhishek Prakash 选题:lkxed 译者:hanszhao80 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出