分类 技术 下的文章

OK03 课程基于 OK02 课程来构建,它教你在汇编中如何使用函数让代码可复用和可读性更好。假设你已经有了 课程 2:OK02 的操作系统,我们将以它为基础。

1、可复用的代码

到目前为止,我们所写的代码都是以我们希望发生的事为顺序来输入的。对于非常小的程序来说,这种做法很好,但是如果我们以这种方式去写一个完整的系统,所写的代码可读性将非常差。我们应该去使用函数。

一个函数是一段可复用的代码片断,可以用于去计算某些答案,或执行某些动作。你也可以称它们为 过程 procedure 例程 routine 子例程 subroutine 。虽然它们都是不同的,但人们几乎都没有正确地使用这个术语。

你应该在数学上遇到了函数的概念。例如,余弦函数应用于一个给定的数时,会得到介于 -1 到 1 之间的另一个数,这个数就是角的余弦。一般我们写成 cos(x) 来表示应用到一个值 x 上的余弦函数。

在代码中,函数可以有多个输入(也可以没有输入),然后函数给出多个输出(也可以没有输出),并可能导致副作用。例如一个函数可以在一个文件系统上创建一个文件,第一个输入是它的名字,第二个输入是文件的长度。

Function as black boxes

函数可以认为是一个“黑匣子”。我们给它输入,然后它给我们输出,而我们不需要知道它是如何工作的。

在像 C 或 C++ 这样的高级代码中,函数是语言的组成部分。在汇编代码中,函数只是我们的创意。

理想情况下,我们希望能够在我们的寄存器中设置一些输入值,然后分支切换到某个地址,然后预期在某个时刻分支返回到我们代码,并通过代码来设置输出值到寄存器。这就是我们所设想的汇编代码中的函数。困难之处在于我们用什么样的方式去设置寄存器。如果我们只是使用平时所接触到的某种方法去设置寄存器,每个程序员可能使用不同的方法,这样你将会发现你很难理解其他程序员所写的代码。另外,编译器也不能像使用汇编代码那样轻松地工作,因为它们压根不知道如何去使用函数。为避免这种困惑,为每个汇编语言设计了一个称为 应用程序二进制接口 Application Binary Interface (ABI)的标准,由它来规范函数如何去运行。如果每个人都使用相同的方法去写函数,这样每个人都可以去使用其他人写的函数。在这里,我将教你们这个标准,而从现在开始,我所写的函数将全部遵循这个标准。

该标准规定,寄存器 r0r1r2r3 将被依次用于函数的输入。如果函数没有输入,那么它不会在意值是什么。如果只需要一个输入,那么它应该总是在寄存器 r0 中,如果它需要两个输入,那么第一个输入在寄存器 r0 中,而第二个输入在寄存器 r1 中,依此类推。输出值也总是在寄存器 r0 中。如果函数没有输出,那么 r0 中是什么值就不重要了。

另外,该标准要求当一个函数运行之后,寄存器 r4r12 的值必须与函数启动时的值相同。这意味着当你调用一个函数时,你可以确保寄存器 r4r12 中的值没有发生变化,但是不能确保寄存器 r0r3 中的值也没有发生变化。

当一个函数运行完成后,它将返回到启动它的代码分支处。这意味着它必须知道启动它的代码的地址。为此,需要一个称为 lr(链接寄存器)的专用寄存器,它总是在保存调用这个函数的指令后面指令的地址。

表 1.1 ARM ABI 寄存器用法

寄存器简介保留规则
r0参数和结果r0r1 用于给函数传递前两个参数,以及函数返回的结果。如果函数返回值不使用它,那么在函数运行之后,它们可以携带任何值。
r1参数和结果
r2参数r2r3 用去给函数传递后两个参数。在函数运行之后,它们可以携带任何值。
r3参数
r4通用寄存器r4r12 用于保存函数运行过程中的值,它们的值在函数调用之后必须与调用之前相同。
r5通用寄存器
r6通用寄存器
r7通用寄存器
r8通用寄存器
r9通用寄存器
r10通用寄存器
r11通用寄存器
r12通用寄存器
lr返回地址当函数运行完成后,lr 中保存了分支的返回地址,但在函数运行完成之后,它将保存相同的地址。
sp栈指针sp 是栈指针,在下面有详细描述。它的值在函数运行完成后,必须是相同的。

通常,函数需要使用很多的寄存器,而不仅是 r0r3。但是,由于 r4r12 必须在函数完成之后值必须保持相同,因此它们需要被保存到某个地方。我们将它们保存到称为栈的地方。

Stack diagram

一个 stack 就是我们在计算中用来保存值的一个很形象的方法。就像是摞起来的一堆盘子,你可以从上到下来移除它们,而添加它们时,你只能从下到上来添加。

在函数运行时,使用栈来保存寄存器值是个非常好的创意。例如,如果我有一个函数需要去使用寄存器 r4r5,它将在一个栈上存放这些寄存器的值。最后用这种方式,它可以再次将它拿回来。更高明的是,如果为了运行完我的函数,需要去运行另一个函数,并且那个函数需要保存一些寄存器,在那个函数运行时,它将把寄存器保存在栈顶上,然后在结束后再将它们拿走。而这并不会影响我保存在寄存器 r4r5 中的值,因为它们是在栈顶上添加的,拿走时也是从栈顶上取出的。

用来表示使用特定的方法将值放到栈上的专用术语,我们称之为那个方法的“ 栈帧 stack frame ”。不是每种方法都使用一个栈帧,有些是不需要存储值的。

因为栈非常有用,它被直接实现在 ARMv6 的指令集中。一个名为 sp(栈指针)的专用寄存器用来保存栈的地址。当需要有值添加到栈上时,sp 寄存器被更新,这样就总是保证它保存的是栈上第一个值的地址。push {r4,r5} 将推送 r4r5 中的值到栈顶上,而 pop {r4,r5} 将(以正确的次序)取回它们。

2、我们的第一个函数

现在,关于函数的原理我们已经有了一些概念,我们尝试来写一个函数。由于是我们的第一个很基础的例子,我们写一个没有输入的函数,它将输出 GPIO 的地址。在上一节课程中,我们就是写到这个值上,但将它写成函数更好,因为我们在真实的操作系统中经常需要用到它,而我们不可能总是能够记住这个地址。

复制下列代码到一个名为 gpio.s 的新文件中。就像在 source 目录中使用的 main.s 一样。我们将把与 GPIO 控制器相关的所有函数放到一个文件中,这样更好查找。

.globl GetGpioAddress
GetGpioAddress:
ldr r0,=0x20200000
mov pc,lr

.globl lbl 使标签 lbl 从其它文件中可访问。

mov reg1,reg2 复制 reg2 中的值到 reg1 中。

这就是一个很简单的完整的函数。.globl GetGpioAddress 命令是通知汇编器,让标签 GetGpioAddress 在所有文件中全局可访问。这意味着在我们的 main.s 文件中,我们可以使用分支指令到标签 GetGpioAddress 上,即便这个标签在那个文件中没有定义也没有问题。

你应该认得 ldr r0,=0x20200000 命令,它将 GPIO 控制器地址保存到 r0 中。由于这是一个函数,我们必须要让它输出到寄存器 r0 中,我们不能再像以前那样随意使用任意一个寄存器了。

mov pc,lr 将寄存器 lr 中的值复制到 pc 中。正如前面所提到的,寄存器 lr 总是保存着方法完成后我们要返回的代码的地址。pc 是一个专用寄存器,它总是包含下一个要运行的指令的地址。一个普通的分支命令只需要改变这个寄存器的值即可。通过将 lr 中的值复制到 pc 中,我们就可以将要运行的下一行命令改变成我们将要返回的那一行。

理所当然这里有一个问题,那就是我们如何去运行这个代码?我们将需要一个特殊的分支类型 bl 指令。它像一个普通的分支一样切换到一个标签,但它在切换之前先更新 lr 的值去包含一个在该分支之后的行的地址。这意味着当函数执行完成后,将返回到 bl 指令之后的那一行上。这就确保了函数能够像任何其它命令那样运行,它简单地运行,做任何需要做的事情,然后推进到下一行。这是理解函数最有用的方法。当我们使用它时,就将它们按“黑匣子”处理即可,不需要了解它是如何运行的,我们只了解它需要什么输入,以及它给我们什么输出即可。

到现在为止,我们已经明白了函数如何使用,下一节我们将使用它。

3、一个大的函数

现在,我们继续去实现一个更大的函数。我们的第一项任务是启用 GPIO 第 16 号针脚的输出。如果它是一个函数那就太好了。我们能够简单地指定一个针脚号和一个函数作为输入,然后函数将设置那个针脚的值。那样,我们就可以使用这个代码去控制任意的 GPIO 针脚,而不只是 LED 了。

将下列的命令复制到 gpio.s 文件中的 GetGpioAddress 函数中。

.globl SetGpioFunction
SetGpioFunction:
cmp r0,#53
cmpls r1,#7
movhi pc,lr

带后缀 ls 的命令只有在上一个比较命令的结果是第一个数字小于或与第二个数字相同的情况下才会被运行。它是无符号的。

带后缀 hi 的命令只有上一个比较命令的结果是第一个数字大于第二个数字的情况下才会被运行。它是无符号的。

在写一个函数时,我们首先要考虑的事情就是输入,如果输入错了我们怎么办?在这个函数中,我们有一个输入是 GPIO 针脚号,而它必须是介于 0 到 53 之间的数字,因为只有 54 个针脚。每个针脚有 8 个函数,被编号为 0 到 7,因此函数编号也必须是 0 到 7 之间的数字。我们可以假设输入应该是正确的,但是当在硬件上使用时,这种做法是非常危险的,因为不正确的值将导致非常糟糕的副作用。所以,在这个案例中,我们希望确保输入值在正确的范围。

为了确保输入值在正确的范围,我们需要做一个检查,即 r0 <= 53 并且 r1 <= 7。首先我们使用前面看到的比较命令去将 r0 的值与 53 做比较。下一个指令 cmpls 仅在前一个比较指令结果是小于或与 53 相同时才会去运行。如果是这种情况,它将寄存器 r1 的值与 7 进行比较,其它的部分都和前面的是一样的。如果最后的比较结果是寄存器值大于那个数字,最后我们将返回到运行函数的代码处。

这正是我们所希望的效果。如果 r0 中的值大于 53,那么 cmpls 命令将不会去运行,但是 movhi 会运行。如果 r0 中的值 <= 53,那么 cmpls 命令会运行,它会将 r1 中的值与 7 进行比较,如果 r1 > 7,movhi 会运行,函数结束,否则 movhi 不会运行,这样我们就确定 r0 <= 53 并且 r1 <= 7。

ls(低于或相同)与 le(小于或等于)有一些细微的差别,以及后缀 hi(高于)和 gt(大于)也一样有一些细微差别,我们在后面将会讲到。

将这些命令复制到上面的代码的下面位置。

push {lr}
mov r2,r0
bl GetGpioAddress

push {reg1,reg2,...} 复制列出的寄存器 reg1reg2、… 到栈顶。该命令仅能用于通用寄存器和 lr 寄存器。

bl lbl 设置 lr 为下一个指令的地址并切换到标签 lbl

这三个命令用于调用我们第一个方法。push {lr} 命令复制 lr 中的值到栈顶,这样我们在后面可以获取到它。当我们调用 GetGpioAddress 时必须要这样做,我们将需要使用 lr 去保存我们函数要返回的地址。

如果我们对 GetGpioAddress 函数一无所知,我们必须假设它改变了 r0r1r2r3 的值 ,并移动我们的值到 r4r5 中,以在函数完成之后保持它们的值一样。幸运的是,我们知道 GetGpioAddress 做了什么,并且我们也知道它仅改变了 r0 为 GPIO 地址,它并没有影响 r1r2r3 的值。因此,我们仅去将 GPIO 针脚号从 r0 中移出,这样它就不会被覆盖掉,但我们知道,可以将它安全地移到 r2 中,因为 GetGpioAddress 并不去改变 r2

最后我们使用 bl 指令去运行 GetGpioAddress。通常,运行一个函数,我们使用一个术语叫“调用”,从现在开始我们将一直使用这个术语。正如我们前面讨论过的,bl 调用一个函数是通过更新 lr 为下一个指令的地址并切换到该函数完成的。

当一个函数结束时,我们称为“返回”。当一个 GetGpioAddress 调用返回时,我们已经知道了 r0 中包含了 GPIO 的地址,r1 中包含了函数编号,而 r2 中包含了 GPIO 针脚号。

我前面说过,GPIO 函数每 10 个保存在一个块中,因此首先我们需要去判断我们的针脚在哪个块中。这似乎听起来像是要使用一个除法,但是除法做起来非常慢,因此对于这些比较小的数来说,不停地做减法要比除法更好。

将下面的代码复制到上面的代码中最下面的位置。

functionLoop$:

cmp r2,#9
subhi r2,#10
addhi r0,#4
bhi functionLoop$
add reg,#val 将数字 val 加到寄存器 reg 的内容上。

这个简单的循环代码将针脚号(r2)与 9 进行比较。如果它大于 9,它将从针脚号上减去 10,并且将 GPIO 控制器地址加上 4,然后再次运行检查。

这样做的效果就是,现在,r2 中将包含一个 0 到 9 之间的数字,它是针脚号除以 10 的余数。r0 将包含这个针脚的函数所设置的 GPIO 控制器的地址。它就如同是 “GPIO 控制器地址 + 4 × (GPIO 针脚号 ÷ 10)”。

最后,将下面的代码复制到上面的代码中最下面的位置。

add r2, r2,lsl #1
lsl r1,r2
str r1,[r0]
pop {pc}

移位参数 reg,lsl #val 表示将寄存器 reg 中二进制表示的数逻辑左移 val 位之后的结果作为与前面运算的操作数。

lsl reg,amt 将寄存器 reg 中的二进制数逻辑左移 amt 中的位数。

str reg,[dst]str reg,[dst,#0] 相同。

pop {reg1,reg2,...} 从栈顶复制值到寄存器列表 reg1reg2、… 仅有通用寄存器与 pc 可以这样弹出值。

这个代码完成了这个方法。第一行其实是乘以 3 的变体。乘法在汇编中是一个大而慢的指令,因为电路需要很长时间才能给出答案。有时使用一些能够很快给出答案的指令会让它变得更快。在本案例中,我们知道 r2 × 3 与 r2 × 2 + r2 是相同的。一个寄存器乘以 2 是非常容易的,因为它可以通过将二进制表示的数左移一位来很方便地实现。

ARMv6 汇编语言其中一个非常有用的特性就是,在使用它之前可以先移动参数所表示的位数。在本案例中,我将 r2 加上 r2 中二进制表示的数左移一位的结果。在汇编代码中,你可以经常使用这个技巧去更快更容易地计算出答案,但如果你觉得这个技巧使用起来不方便,你也可以写成类似 mov r3,r2add r2,r3add r2,r3 这样的代码。

现在,我们可以将一个函数的值左移 r2 中所表示的位数。大多数对数量的指令(比如 addsub)都有一个可以使用寄存器而不是数字的变体。我们执行这个移位是因为我们想去设置表示针脚号的位,并且每个针脚有三个位。

然后,我们将函数计算后的值保存到 GPIO 控制器的地址上。我们在循环中已经算出了那个地址,因此我们不需要像 OK01 和 OK02 中那样在一个偏移量上保存它。

最后,我们从这个方法调用中返回。由于我们将 lr 推送到了栈上,因此我们 pop pc,它将复制 lr 中的值并将它推送到 pc 中。这个操作类似于 mov pc,lr,因此函数调用将返回到运行它的那一行上。

敏锐的人可能会注意到,这个函数其实并不能正确工作。虽然它将 GPIO 针脚函数设置为所要求的值,但它会导致在同一个块中的所有的 10 个针脚的函数都归 0!在一个大量使用 GPIO 针脚的系统中,这将是一个很恼人的问题。我将这个问题留给有兴趣去修复这个函数的人,以确保只设置相关的 3 个位而不去覆写其它位,其它的所有位都保持不变。关于这个问题的解决方案可以在本课程的下载页面上找到。你可能会发现非常有用的几个函数是 and,它是计算两个寄存器的布尔与函数,mvns 是计算布尔非函数,而 orr 是计算布尔或函数。

4、另一个函数

现在,我们已经有了能够管理 GPIO 针脚函数的函数。我们还需要写一个能够打开或关闭 GPIO 针脚的函数。我们不需要写一个打开的函数和一个关闭的函数,只需要一个函数就可以做这两件事情。

我们将写一个名为 SetGpio 的函数,它将 GPIO 针脚号作为第一个输入放入 r0 中,而将值作为第二个输入放入 r1 中。如果该值为 0,我们将关闭针脚,而如果为非零则打开针脚。

将下列的代码复制粘贴到 gpio.s 文件的结尾部分。

.globl SetGpio
SetGpio:
pinNum .req r0
pinVal .req r1
alias .req reg 设置寄存器 reg 的别名为 alias

我们再次需要 .globl 命令,标记它为其它文件可访问的全局函数。这次我们将使用寄存器别名。寄存器别名允许我们为寄存器使用名字而不仅是 r0r1。到目前为止,寄存器别名还不是很重要,但随着我们后面写的方法越来越大,它将被证明非常有用,现在开始我们将尝试使用别名。当在指令中使用到 pinNum .req r0 时,它的意思是 pinNum 表示 r0

将下面的代码复制粘贴到上述的代码下面位置。

cmp pinNum,#53
movhi pc,lr
push {lr}
mov r2,pinNum
.unreq pinNum
pinNum .req r2
bl GetGpioAddress
gpioAddr .req r0
.unreq alias 删除别名 alias

就像在函数 SetGpio 中所做的第一件事情是检查给定的针脚号是否有效一样。我们需要同样的方式去将 pinNumr0)与 53 进行比较,如果它大于 53 将立即返回。一旦我们想要再次调用 GetGpioAddress,我们就需要将 lr 推送到栈上来保护它,将 pinNum 移动到 r2 中。然后我们使用 .unreq 语句来删除我们给 r0 定义的别名。因为针脚号现在保存在寄存器 r2 中,我们希望别名能够反映这个变化,因此我们从 r0 移走别名,重新定义到 r2。你应该每次在别名使用结束后,立即删除它,这样当它不再存在时,你就不会在后面的代码中因它而产生错误。

然后,我们调用了 GetGpioAddress,并且我们创建了一个指向 r0的别名以反映此变化。

将下面的代码复制粘贴到上述代码的后面位置。

pinBank .req r3
lsr pinBank,pinNum,#5a
lsl pinBank,#2
add gpioAddr,pinBank
.unreq pinBank
lsr dst,src,#valsrc 中二进制表示的数右移 val 位,并将结果保存到 dst

对于打开和关闭 GPIO 针脚,每个针脚在 GPIO 控制器上有两个 4 字节组。第一个 4 字节组每个位控制前 32 个针脚,而第二个 4 字节组控制剩下的 22 个针脚。为了判断我们要设置的针脚在哪个 4 字节组中,我们需要将针脚号除以 32。幸运的是,这很容易,因为它等价于将二进制表示的针脚号右移 5 位。因此,在本案例中,我们将 r3 命名为 pinBank,然后计算 pinNum ÷ 32。因为它是一个 4 字节组,我们需要将它与 4 相乘的结果。它与二进制表示的数左移 2 位相同,这就是下一行的命令。你可能想知道我们能否只将它右移 3 位呢,这样我们就不用先右移再左移。但是这样做是不行的,因为当我们做 ÷ 32 时答案有些位可能被舍弃,而如果我们做 ÷ 8 时却不会这样。

现在,gpioAddr 的结果有可能是 20200000 16(如果针脚号介于 0 到 31 之间),也有可能是 20200004 16(如果针脚号介于 32 到 53 之间)。这意味着如果加上 28 10,我们将得到打开针脚的地址,而如果加上 40 10 ,我们将得到关闭针脚的地址。由于我们用完了 pinBank ,所以在它之后立即使用 .unreq 去删除它。

将下面的代码复制粘贴到上述代码的下面位置。

and pinNum,#31
setBit .req r3
mov setBit,#1
lsl setBit,pinNum
.unreq pinNum
and reg,#val 计算寄存器 reg 中的数与 val 的布尔与。

该函数的下一个部分是产生一个正确的位集合的数。至于 GPIO 控制器去打开或关闭针脚,我们在针脚号除以 32 的余数里设置了位的数。例如,设置 16 号针脚,我们需要第 16 位设置数字为 1 。设置 45 号针脚,我们需要设置第 13 位数字为 1,因为 45 ÷ 32 = 1 余数 13。

这个 and 命令计算我们需要的余数。它是这样计算的,在两个输入中所有的二进制位都是 1 时,这个 and 运算的结果就是 1,否则就是 0。这是一个很基础的二进制操作,and 操作非常快。我们给定的输入是 “pinNum and 31 10 = 11111 2”。这意味着答案的后 5 位中只有 1,因此它肯定是在 0 到 31 之间。尤其是在 pinNum 的后 5 位的位置是 1 的地方它只有 1。这就如同被 32 整除的余数部分。就像 31 = 32 - 1 并不是巧合。

binary division example

代码的其余部分使用这个值去左移 1 位。这就有了创建我们所需要的二进制数的效果。

将下面的代码复制粘贴到上述代码的下面位置。

teq pinVal,#0
.unreq pinVal
streq setBit,[gpioAddr,#40]
strne setBit,[gpioAddr,#28]
.unreq setBit
.unreq gpioAddr
pop {pc}
teq reg,#val 检查寄存器 reg 中的数字与 val 是否相等。

这个代码结束了该方法。如前面所说,当 pinVal 为 0 时,我们关闭它,否则就打开它。teq(等于测试)是另一个比较操作,它仅能够测试是否相等。它类似于 cmp ,但它并不能算出哪个数大。如果你只是希望测试数字是否相同,你可以使用 teq

如果 pinVal 是 0,我们将 setBit 保存在 GPIO 地址偏移 40 的位置,我们已经知道,这样会关闭那个针脚。否则将它保存在 GPIO 地址偏移 28 的位置,它将打开那个针脚。最后,我们通过弹出 pc 返回,这将设置它为我们推送链接寄存器时保存的值。

5、一个新的开始

在完成上述工作后,我们终于有了我们的 GPIO 函数。现在,我们需要去修改 main.s 去使用它们。因为 main.s 现在已经有点大了,也更复杂了。将它分成两节将是一个很好的设计。到目前为止,我们一直使用的 .init 应该尽可能的让它保持小。我们可以更改代码来很容易地反映出这一点。

将下列的代码插入到 main.s 文件中 _start: 的后面:

b main

.section .text
main:
mov sp,#0x8000

在这里重要的改变是引入了 .text 节。我设计了 makefile 和链接器脚本,它将 .text 节(它是默认节)中的代码放在地址为 8000 16.init 节之后。这是默认加载地址,并且它给我们提供了一些空间去保存栈。由于栈存在于内存中,它也有一个地址。栈向下增长内存,因此每个新值都低于前一个地址,所以,这使得栈顶是最低的一个地址。

Layout diagram of operating system

图中的 “ATAGs” 节的位置保存了有关树莓派的信息,比如它有多少内存,默认屏幕分辨率是多少。

用下面的代码替换掉所有设置 GPIO 函数针脚的代码:

pinNum .req r0
pinFunc .req r1
mov pinNum,#16
mov pinFunc,#1
bl SetGpioFunction
.unreq pinNum
.unreq pinFunc

这个代码将使用针脚号 16 和函数编号 1 去调用 SetGpioFunction。它的效果就是启用了 OK LED 灯的输出。

用下面的代码去替换打开 OK LED 灯的代码:

pinNum .req r0
pinVal .req r1
mov pinNum,#16
mov pinVal,#0
bl SetGpio
.unreq pinNum
.unreq pinVal

这个代码使用 SetGpio 去关闭 GPIO 第 16 号针脚,因此将打开 OK LED。如果我们(将第 4 行)替换成 mov pinVal,#1 它将关闭 LED 灯。用以上的代码去替换掉你关闭 LED 灯的旧代码。

6、继续向目标前进

但愿你能够顺利地在你的树莓派上测试我们所做的这一切。到目前为止,我们已经写了一大段代码,因此不可避免会出现错误。如果有错误,可以去查看我们的排错页面。

如果你的代码已经正常工作,恭喜你。虽然我们的操作系统除了做 课程 2:OK02 中的事情,还做不了别的任何事情,但我们已经学会了函数和格式有关的知识,并且我们现在可以更好更快地编写新特性了。现在,我们在操作系统上修改 GPIO 寄存器将变得非常简单,而它就是用于控制硬件的!

课程 4:OK04 中,我们将处理我们的 wait 函数,目前,它的时间控制还不精确,这样我们就可以更好地控制我们的 LED 灯了,进而最终控制所有的 GPIO 针脚。


via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok03.html

作者:Robert Mullins 选题:lujun9972 译者:qhwdw 校对:wxy

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

简介

XML 和 JSON 是现今互联网中最常用的两种数据交换格式。XML 格式由 W3C 于 1996 年提出。JSON 格式由 Douglas Crockford 于 2002 年提出。虽然这两种格式的设计目标并不相同,但它们常常用于同一个任务,也就是数据交换中。XML 和 JSON 的文档都很完善(RFC 7159RFC 4825),且都同时具有 人类可读性 human-readable 机器可读性 machine-readable 。这两种格式并没有哪一个比另一个更强,只是各自适用的领域不用。(LCTT 译注:W3C 是互联网联盟,制定了各种 Web 相关的标准,如 HTML、CSS 等。Douglas Crockford 除了制定了 JSON 格式,还致力于改进 JavaScript,开发了 JavaScript 相关工具 JSLintJSMin

XML 的优点

XML 与 JSON 相比有很多优点。二者间最大的不同在于 XML 可以通过在标签中添加属性这一简单的方法来存储 元数据 metadata 。而使用 JSON 时需要创建一个对象,把元数据当作对象的成员来存储。虽然二者都能达到存储元数据的目的,但在这一情况下 XML 往往是更好的选择,因为 JSON 的表达形式会让客户端程序开发人员误以为要将数据转换成一个对象。举个例子,如果你的 C++ 程序需要使用 JSON 格式发送一个附带元数据的整型数据,需要创建一个对象,用对象中的一个 名称/值对 name/value pair 来记录整型数据的值,再为每一个附带的属性添加一个名称/值对。接收到这个 JSON 的程序在读取后很可能把它当成一个对象,可事实并不是这样。虽然这是使用 JSON 传递元数据的一种变通方法,但他违背了 JSON 的核心理念:“ JSON 的结构与常规的程序语言中的结构相对应,而无需修改。 JSON’s structures look like conventional programming language structures. No restructuring is necessary. 1

虽然稍后我会说这也是 XML 的一个缺点,但 XML 中对命名冲突、 前缀 prefix 的处理机制赋予了它 JSON 所不具备的能力。程序员们可以通过前缀来把统一名称给予两个不同的实体。 2 当不同的实体在客户端中使用的名称相同时,这一特性会非常有用。

XML 的另一个优势在于大多数的浏览器可以把它以 具有高可读性和强组织性的方式 highly readable and organized way 展现给用户。XML 的树形结构让它易于结构化,浏览器也让用户可以自行展开或折叠树中的元素,这简直就是调试的福音。

XML 对比 JSON 有一个很重要的优势就是它可以记录 混合内容 mixed content 。例如在 XML 中处理包含结构化标记的字符串时,程序员们只要把带有标记的文本放在一个标签内就可以了。可因为 JSON 只包含数据,没有用于指明标签的简单方式,虽然可以使用处理元数据的解决方法,但这总有点滥用之嫌。

JSON 的优点

JSON 自身也有很多优点。其中最显而易见的一点就是 JSON 比 XML 简洁得多。因为 XML 中需要打开和关闭标签,而 JSON 使用名称/值对表示数据,使用简单的 {} 来标记对象,[] 来标记数组,, 来表示数据的分隔,: 表示名称和值的分隔。就算是使用 gzip 压缩,JSON 还是比 XML 要小,而且耗时更少。 3 正如 Sumaray 和 Makki 在实验中指出的那样,JSON 在很多方面都比 XML 更具优势,得出同样结果的还有 Nurseitov、Paulson、Reynolds 和 Izurieta。首先,由于 JSON 文件天生的简洁性,与包含相同信息的 XML 相比,JSON 总是更小,这意味着更快的传输和处理速度。第二,在不考虑大小的情况下,两组研究 4 5 表明使用 JSON 执行序列化和反序列化的速度显著优于使用 XML。第三,后续的研究指出 JSON 的处理在 CPU 资源的使用上也优于 XML。研究人员发现 JSON 在总体上使用的资源更少,其中更多的 CPU 资源消耗在用户空间,系统空间消耗的 CPU 资源较少。这一实验是在 RedHat 的设备上进行的,RedHat 表示更倾向于在用户空间使用 CPU 资源。 6 不出意外,Sumaray 和 Makki 在研究里还说明了在移动设备上 JSON 的性能也优于 XML。 7 这是有道理的,因为 JSON 消耗的资源更少,而移动设备的性能也更弱。

JSON 的另一个优点在于其对对象和数组的表述和 宿主语言 host language 中的数据结构相对应,例如 对象 object 记录 record 结构体 struct 字典 dictionary 哈希表 hash table 键值列表 keyed list 还有 数组 array 向量 vector 列表 list ,以及对象组成的数组等等。 8 虽然 XML 里也能表达这些数据结构,也只需调用一个函数就能完成解析,而往往需要更多的代码才能正确的完成 XML 的序列化和反序列化处理。而且 XML 对于人类来说不如 JSON 那么直观,XML 标准缺乏对象、数组的标签的明确定义。当结构化的标记可以替代嵌套的标签时,JSON 的优势极为突出。JSON 中的花括号和中括号则明确表示了数据的结构,当然这一优势也包含前文中的问题,在表示元数据时 JSON 不如 XML 准确。

虽然 XML 支持 命名空间 namespace 前缀 prefix ,但这不代表 JSON 没有处理命名冲突的能力。比起 XML 的前缀,它处理命名冲突的方式更简洁,在程序中的处理也更自然。在 JSON 里,每一个对象都在它自己的命名空间中,因此不同对象内的元素名称可以随意重复。在大多数编程语言中,不同的对象中的成员可以包含相同的名字,所以 JSON 根据对象进行名称区分的规则在处理时更加自然。

也许 JSON 比 XML 更优的部分是因为 JSON 是 JavaScript 的子集,所以在 JavaScript 代码中对它的解析或封装都非常的自然。虽然这看起来对 JavaScript 程序非常有用,而其他程序则不能直接从中获益,可实际上这一问题已经被很好的解决了。现在 JSON 的网站的列表上展示了 64 种不同语言的 175 个工具,它们都实现了处理 JSON 所需的功能。虽然我不能评价大多数工具的质量,但它们的存在明确了开发者社区拥抱 JSON 这一现象,而且它们切实简化了在不同平台使用 JSON 的难度。

二者的动机

简单地说,XML 的目标是标记文档。这和 JSON 的目标想去甚远,所以只要用得到 XML 的地方就尽管用。它使用树形的结构和包含语义的文本来表达混合内容以实现这一目标。在 XML 中可以表示数据的结构,但这并不是它的长处。

JSON 的目标是用于数据交换的一种结构化表示。它直接使用对象、数组、数字、字符串、布尔值这些元素来达成这一目标。这完全不同于文档标记语言。正如上面说的那样,JSON 没有原生支持 混合内容 mixed content 的记录。

软件

这些主流的开放 API 仅提供 XML: 亚马逊产品广告 API Amazon Product Advertising API

这些主流 API 仅提供 JSON: 脸书图 API Facebook Graph API 谷歌地图 API Google Maps API 推特 API Twitter API 、AccuWeather API、Pinterest API、Reddit API、Foursquare API。

这些主流 API 同时提供 XML 和 JSON: 谷歌云存储 Google Cloud Storage 领英 API Linkedin API 、Flickr API。

根据 可编程网络 Programmable Web 9 的数据,最流行的 10 个 API 中只有一个是仅提供 XML 且不支持 JSON 的。其他的要么同时支持 XML 和 JSON,要么只支持 JSON。这表明了大多数应用开发者都更倾向于使用支持 JSON 的 API,原因大概是 JSON 更快的处理速度与良好口碑,加之与 XML 相比更加轻量。此外,大多数 API 只是传递数据而非文档,所以 JSON 更加合适。例如 Facebook 的重点在于用户的交流与帖子,谷歌地图则主要处理坐标和地图信息,AccuWeather 就只传递天气数据。总之,虽然不能说天气 API 在使用时究竟是 JSON 用的多还是 XML 用的多,但是趋势明确偏向了 JSON。 10 11

这些主流的桌面软件仍然只是用 XML:Microsoft Word、Apache OpenOffice、LibraOffice。

因为这些软件需要考虑引用、格式、存储等等,所以比起 JSON,XML 优势更大。另外,这三款程序都支持混合内容,而 JSON 在这一点上做得并不如 XML 好。举例说明,当用户使用 Microsoft Word 编辑一篇论文时,用户需要使用不同的文字字形、文字大小、文字颜色、页边距、段落格式等,而 XML 结构化的组织形式与标签属性生来就是为了表达这些信息的。

这些主流的数据库支持 XML:IBM DB2、Microsoft SQL Server、Oracle Database、PostgresSQL、BaseX、eXistDB、MarkLogic、MySQL。

这些是支持 JSON 的主流数据库:MongoDB、CouchDB、eXistDB、Elastisearch、BaseX、MarkLogic、OrientDB、Oracle Database、PostgreSQL、Riak。

在很长一段时间里,SQL 和关系型数据库统治着整个数据库市场。像 甲骨文 Oracle 微软 Microsoft 这样的软件巨头都提供这类数据库,然而近几年 NoSQL 数据库正逐步受到开发者的青睐。也许是正巧碰上了 JSON 的普及,大多数 NoSQL 数据库都支持 JSON,像 MongoDB、CouchDB 和 Riak 这样的数据库甚至使用 JSON 来存储数据。这些数据库有两个重要的特性是它们适用于现代网站:一是它们与关系型数据库相比 更容易扩展 more scalable ;二是它们设计的目标就是 web 运行所需的核心组件。 12 由于 JSON 更加轻量,又是 JavaScript 的子集,所以很适合 NoSQL 数据库,并且让这两个品质更容易实现。此外,许多旧的关系型数据库增加了 JSON 支持,例如 Oracle Database 和 PostgreSQL。由于 XML 与 JSON 间的转换比较麻烦,所以大多数开发者会直接在他们的应用里使用 JSON,因此开发数据库的公司才有支持 JSON 的理由。(LCTT 译注:NoSQL 是对不同于传统的关系数据库的数据库管理系统的统称。参考来源 13

未来

对互联网的种种变革中,最让人期待的便是 物联网 Internet of Things (IoT)。这会给互联网带来大量计算机之外的设备,例如手表、温度计、电视、冰箱等等。这一势头的发展良好,预期在不久的将来迎来爆发式的增长。据估计,到 2020 年时会有 260 亿 到 2000 亿的物联网设备被接入互联网。 14 15 几乎所有的物联网设备都是小型设备,因此性能比笔记本或台式电脑要弱很多,而且大多数都是嵌入式系统。因此,当它们需要与互联网上的系统交换数据时,更轻量、更快速的 JSON 自然比 XML 更受青睐。 16 受益于 JSON 在 web 上的快速普及,与 XML 相比,这些新的物联网设备更有可能从使用 JSON 中受益。这是一个典型的梅特卡夫定律的例子,无论是 XML 还是 JSON,抑或是什么其他全新的格式,现存的设备和新的设备都会从支持最广泛使用的格式中受益。

Node.js 是一款服务器端的 JavaScript 框架,随着她的诞生与快速成长,与 MongoDB 等 NoSQL 数据库一起,让全栈使用 JavaScript 开发成为可能。这些都预示着 JSON 光明的未来,这些软件的出现让 JSON 运用在全栈开发的每一个环节成为可能,这将使应用更加轻量,响应更快。这也是任何应用的追求之一,所以,全栈使用 JavaScript 的趋势在不久的未来都不会消退。 17

此外,另一个应用开发的趋势是从 SOAP 转向 REST。 18 19 20 XML 和 JSON 都可以用于 REST,可 SOAP 只能使用 XML。

从这些趋势中可以推断,JSON 的发展将统一 Web 的信息交换格式,XML 的使用率将继续降低。虽然不应该把 JSON 吹过头了,因为 XML 在 Web 中的使用依旧很广,而且它还是 SOAP 的唯一选择,可考虑到 SOAP 到 REST 的迁移,NoSQL 数据库和全栈 JavaScript 的兴起,JSON 卓越的性能,我相信 JSON 很快就会在 Web 开发中超过 XML。至于其他领域,XML 比 JSON 更好的情况并不多。

角注


  1. Introducing JSON
  2. XML Tutorial
  3. JSON vs. XML: Some hard numbers about verbosity
  4. Comparison of JSON and XML Data Interchange Formats: A Case Study
  5. A comparison of data serialization formats for optimal efficiency on a mobile platform
  6. Comparison of JSON and XML Data Interchange Formats: A Case Study
  7. A comparison of data serialization formats for optimal efficiency on a mobile platform
  8. Introducing JSON
  9. Most Popular APIs: At Least One Will Surprise You
  10. Why JSON will continue to push XML out of the picture
  11. Thousands of APIs Paint a Bright Future for the Web
  12. Why JSON will continue to push XML out of the picture
  13. How JSON sparked NoSQL – and will return to the RDBMS fold
  14. A Simple Explanation Of ‘The Internet Of Things’
  15. Proofpoint Uncovers Internet of Things (IoT) Cyberattack
  16. Why JSON will continue to push XML out of the picture
  17. Why JSON will continue to push XML out of the picture
  18. Thousands of APIs Paint a Bright Future for the Web
  19. 3,000 Web APIs: Trends From A Quickly Growing Directory
  20. How REST replaced SOAP on the Web: What it means to you

via: https://www.cs.tufts.edu/comp/150IDS/final_papers/tstras01.1/FinalReport/FinalReport.html

作者:TOM STRASSNER 选题:lujun9972 译者:wwhio 校对:wxy

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

在 Linux 中创建用户账号时,设置用户密码是一件基本的事情。每个人都使用 passwd 命令跟上用户名,比如 passwd USERNAME 来为用户设置密码。

确保你一定要设置一个难以猜测的密码,这可以帮助你使系统更安全。我的意思是,密码应该是字母、符号和数字的组合。此外,出于安全原因,我建议你至少每月更改一次密码。

当你使用 passwd 命令时,它会要求你输入两次密码来设置。这是一种设置用户密码的原生方法。

如果你不想两次更新密码,并希望以不同的方式进行更新,怎么办呢?当然,这可以的,有可能做到。

如果你是 Linux 管理员,你可能已经多次问过下面的问题。你可能、也可能没有得到这些问题的答案。

无论如何,不要担心,我们会回答你所有的问题。

  • 如何用一条命令更改用户密码?
  • 如何在 Linux 中为多个用户更改为相同的密码?
  • 如何在 Linux 中更改多个用户的密码?
  • 如何在 Linux 中为多个用户更改为不同的密码?
  • 如何在多个 Linux 服务器中更改用户的密码?
  • 如何在多个 Linux 服务器中更改多个用户的密码?

方法-1:使用 passwd 命令

passwd 命令是在 Linux 中为用户设置、更改密码的标准方法。以下是标准方法。

# passwd renu
Changing password for user renu.
New password:
BAD PASSWORD: The password contains the user name in some form
Retype new password:
passwd: all authentication tokens updated successfully.

如果希望在一条命令中设置或更改密码,运行以下命令。它允许用户在一条命令中更新密码。

# echo "new_password" | passwd --stdin thanu
Changing password for user thanu.
passwd: all authentication tokens updated successfully.

方法-2:使用 chpasswd 命令

chpasswd 是另一个命令,允许我们为 Linux 中的用户设置、更改密码。如果希望在一条命令中使用 chpasswd 命令更改用户密码,用以下格式。

# echo "thanu:new_password" | chpasswd

方法-3:如何为多个用户设置不同的密码

如果你要为 Linux 中的多个用户设置、更改密码,并且使用不同的密码,使用以下脚本。

为此,首先我们需要使用以下命令获取用户列表。下面的命令将列出拥有 /home 目录的用户,并将输出重定向到 user-list.txt 文件。

# cat /etc/passwd | grep "/home" | cut -d":" -f1 > user-list.txt

使用 cat 命令列出用户。如果你不想重置特定用户的密码,那么从列表中移除该用户。

# cat user-list.txt
centos
magi
daygeek
thanu
renu

创建以下 shell 小脚本来实现此目的。

# vi password-update.sh

#!/bin/sh
for user in `more user-list.txt`
do
echo "[email protected]" | passwd --stdin "$user"
chage -d 0 $user
done

password-update.sh 文件设置可执行权限。

# chmod +x password-update.sh

最后运行脚本来实现这一目标。

# ./password-up.sh

magi
Changing password for user magi.
passwd: all authentication tokens updated successfully.
daygeek
Changing password for user daygeek.
passwd: all authentication tokens updated successfully.
thanu
Changing password for user thanu.
passwd: all authentication tokens updated successfully.
renu
Changing password for user renu.
passwd: all authentication tokens updated successfully.

方法-4:如何为多个用户设置相同的密码

如果要在 Linux 中为多个用户设置、更改相同的密码,使用以下脚本。

# vi password-update.sh

#!/bin/sh
for user in `more user-list.txt`
do
echo "new_password" | passwd --stdin "$user"
chage -d 0 $user
done

方法-5:如何在多个服务器中更改用户密码

如果希望更改多个服务器中的用户密码,使用以下脚本。在本例中,我们将更改 renu 用户的密码,确保你必须提供你希望更新密码的用户名而不是我们的用户名。

确保你必须将服务器列表保存在 server-list.txt 文件中,每个服务器应该在单独一行中。

# vi password-update.sh

#!/bin/bash
for server in `cat server-list.txt`
do
ssh [email protected]$server 'passwd --stdin renu <<EOF
new_passwd
new_passwd
EOF';
done

你将得到与我们类似的输出。

# ./password-update.sh

New password: BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple
Retype new password: Changing password for user renu.
passwd: all authentication tokens updated successfully.
New password: BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple
Retype new password: Changing password for user renu.
passwd: all authentication tokens updated successfully.

方法-6:如何使用 pssh 命令更改多个服务器中的用户密码

pssh 是一个在多个主机上并行执行 ssh 连接的程序。它提供了一些特性,例如向所有进程发送输入,向 ssh 传递密码,将输出保存到文件以及超时处理。导航到以下链接以了解关于 PSSH 命令的更多信息。

# pssh -i -h /tmp/server-list.txt "printf '%s\n' new_pass new_pass | passwd --stdin root"

你将获得与我们类似的输出。

[1] 07:58:07 [SUCCESS] CentOS.2daygeek.com
Changing password for user root.
passwd: all authentication tokens updated successfully.
Stderr: New password: BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple
Retype new password:
[2] 07:58:07 [SUCCESS] ArchLinux.2daygeek.com
Changing password for user root.
passwd: all authentication tokens updated successfully.
Stderr: New password: BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple

方法-7:如何使用 chpasswd 命令更改多个服务器中的用户密码

或者,我们可以使用 chpasswd 命令更新多个服务器中的用户密码。

# ./password-update.sh

#!/bin/bash
for server in `cat server-list.txt`
do
ssh [email protected]$server 'echo "magi:new_password" | chpasswd'
done

方法-8:如何使用 chpasswd 命令在 Linux 服务器中更改多个用户的密码

为此,首先创建一个文件,以下面的格式更新用户名和密码。在本例中,我创建了一个名为 user-list.txt 的文件。

参考下面的详细信息。

# cat user-list.txt
magi:new@123
daygeek:new@123
thanu:new@123
renu:new@123

创建下面的 shell 小脚本来实现这一点。

# vi password-update.sh

#!/bin/bash
for users in `cat user-list.txt`
do
echo $users | chpasswd
done

via: https://www.2daygeek.com/linux-passwd-chpasswd-command-set-update-change-users-password-in-linux-using-shell-script/

作者:Vinoth Kumar 选题:lujun9972 译者:MjSeven 校对: wxy

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

了解如何选择最适合你的需求的开源数据库。

在现代的企业级技术领域中,开源软件已经成为了一股不可忽视的重要力量。借助 开源运动 open source movement 的东风,涌现除了许多重大的技术突破。

个中原因显而易见,尽管一些基于 Linux 的开源网络标准可能不如专有厂商的那么受欢迎,但是不同制造商的智能设备之间能够互相通信,开源技术功不可没。当然也有不少人认为开源开发出来的应用比厂商提供的产品更加好,所以无论如何,使用开源数据库进行开发确实是相当有利的。

和其它类型的应用软件一样,不同的开源数据库管理系统之间在功能和特性上可能会存在着比较大的差异。换言之,不是所有的开源数据库都是平等的。因此,如果要为整个组织选择一个开源数据库,那么应该重点考察数据库是否对用户友好、是否能够持续适应团队需求、是否能够提供足够安全的功能等方面的因素。

出于这方面考虑,我们在这篇文章中对一些开源数据库进行了概述和优缺点对比。遗憾的是,我们必须忽略一些最常用的数据库。值得注意的是,MongoDB 最近更改了它的许可证,因此它已经不是真正的开源产品了。从商业角度来看,这个决定是很有意义的,因为 MongoDB 已经成为了数据库托管实际上的解决方案,约 27000 家公司在使用它,但这也意味着 MongoDB 已经不再被视为真正的开源产品。

另外,自从 MySQL 被 Oracle 收购之后,这个产品就已经不再具有开源性质了,MySQL 可以说是数十年来首选的开源数据库。然而,这为其它真正的开源数据库解决方案提供了挑战它的空间。

下面是三个值得考虑的开源数据库。

PostgreSQL

没有 PostgreSQL 的开源数据库清单肯定是不完整的。PostgreSQL 一直都是各种规模企业的首选解决方案。Oracle 对 MySQL 的收购在当时来说可能具有一定的商业意义,但是随着云存储的日益壮大,开发者对 MySQL 的依赖程度或许并不如以前那么大了

尽管 PostgreSQL 不是一个最近几年才面世的新产品,但它却是借助了 MySQL 相对衰落的机会才逐渐成为最受欢迎的开源数据库之一。由于它和 MySQL 的工作方式非常相似,因此很多热衷于使用开源软件的开发者都纷纷转向 PostgreSQL。

优势

  • 目前 PostgreSQL 最显著的优点是它的核心算法的效率,这意味着它的性能优于许多宣称更先进数据库。这一点在处理大型数据集的时候就可以很明显地体现出来了,否则 I/O 处理会成为瓶颈。
  • PostgreSQL 也是最灵活的开源数据库之一,使用 Python、Perl、Java、Ruby、C 或者 R 都能够很方便地调用数据库。
  • 作为最常用的几个开源数据库之中,PostgreSQL 的社区支持是做得最好的。

劣势

  • 在数据量比较大的时候,PostgreSQL 的效率毋庸置疑是很高的,但对于数据量较小的情况,使用 PostgreSQL 就显得不如其它的一些工具快了。
  • 尽管拥有一个很优秀的社区支持,但 PostgreSQL 的核心文档仍然需要作出改进。
  • 如果你需要使用并行计算或者集群化等高级工具,就需要安装 PostgreSQL 的第三方插件。尽管官方有计划将这些功能逐步添加到主要版本当中,但可能会需要再等待好几年才能出现在标准版本中。

MariaDB

MariaDB 是 MySQL 的真正开源的发行版本(在 GNU GPLv2 下发布)。在 Oracle 收购 MySQL 之后,MySQL 的一些核心开发人员认为 Oracle 会破坏 MySQL 的开源理念,因此建立了 MariaDB 这个独立的分支。

MariaDB 在开发过程中替换了 MySQL 的几个关键组件,但仍然尽可能地保持兼容 MySQL。MariaDB 使用了 Aria 作为存储引擎,这个存储引擎既可以作为事务式引擎,也可以作为非事务式引擎。在 MariaDB 分叉出来之前,就有一些人推测 Aria 会成为 MySQL 未来版本中的标准引擎。

优势

  • 由于 MariaDB 频繁进行安全发布,很多用户选择使用 MariaDB 而不选择 MySQL。尽管这不一定代表 MariaDB 会比 MySQL 更加安全,但确实表明它的开发社区对安全性十分重视。
  • 有一些人认为,MariaDB 的主要优点就是它在坚持开源的同时会与 MySQL 保持高度兼容,这就意味着从 MySQL 向 MariaDB 的迁移会非常容易。
  • 也正是由于这种兼容性,MariaDB 也可以和其它常用于 MySQL 的语言配合使用,因此从 MySQL 迁移到 MariaDB 之后,学习和调试代码的时间成本会非常低。
  • 你可以将 WordPress 和 MariaDB(而不是 MySQL)配合使用从而获得更好的性能和更丰富的功能。WordPress 是最受欢迎的 内容管理系统 Content Management System (CMS),占据了一半的互联网份额,并且拥有活跃的开源开发者社区。各种第三方插件在 WordPress 和 MariaDB 配合使用时都能够正常工作。

劣势

  • MariaDB 有时会变得比较臃肿,尤其是它的 IDX 日志文件在长期使用之后会变得非常大,最终导致性能下降。
  • 缓存是 MariaDB 的另一个工作领域,并没有期望中那么快,这可能会让人有所失望。
  • 尽管 MariaDB 最初承诺兼容 MySQL,但目前 MariaDB 已经不是完全兼容 MySQL。如果要从 MySQL 迁移到 MariaDB,就需要额外做一些兼容工作。

SQLite

SQLite 可以说是世界上实现最多的数据库引擎,因为它被很多流行的 web 浏览器、操作系统和手机所采用。它最初是作为 MySQL 的轻量级分支所开发的。SQLite 和很多其它的数据库不同,它不采用客户端-服务端的引擎架构,而是将整个软件嵌入到每个实现当中。

这样的架构让 SQLite 拥有一个强大的优势,就是在嵌入式系统或者分布式系统中,每台机器都搭载了数据库的整个实现。这样的做法减少了系统间的调用,从而大大提高了数据库的性能。

优势

  • 如果你需要构建和实现一个小型数据库,SQLite 可能是最好的选择。它小而灵活,不需要费工夫寻求各种变通方案,就可以在嵌入式系统中实现。
  • SQLite 体积很小,因此速度极快。其它的一些高级数据库可能会使用复杂的优化方式来提高效率,但SQLite 采用了一种更简单的方法:通过减小数据库及其处理软件的大小,以使处理的数据更少。
  • SQLite 被广泛采用也导致它可能是兼容性最高的数据库。如果你希望将应用程序集成到智能手机上,这一点尤为重要:只要是可以工作于广泛环境中的第三方应用程序,就可以原生运行于 iOS 上。

劣势

  • SQLite 的体积小意味着它缺少了很多其它大型数据库的常见功能。例如数据加密就是抵御黑客攻击的标准功能,而 SQLite 却没有内置这个功能。
  • SQLite 的广泛流行和源码公开使它易于使用,但是也让它更容易遭受攻击。这是它最大的劣势。SQLite 经常被发现高危的漏洞,例如最近的 Magellan
  • 尽管 SQLite 单文件的方式拥有速度上的优势,但是要使用它实现多用户环境却比较困难。

哪个开源数据库才是最好的?

当然,对于开源数据库的选择还是取决于业务的需求,尤其是系统的体量。对于小型数据库或者是使用量比较小的数据库,可以使用比较轻量级的解决方案,这样不仅可以加快实现的速度,而且由于系统的复杂程度不算太高,花在调试上的时间成本也不会太高。

而对于大型的系统,尤其是在成长性企业中,最好还是花时间使用更复杂的数据库(例如 PostgreSQL)。这是一个磨刀不误砍柴工的选择,能够让你不至于在后期再重新选择另一款数据库。


via: https://opensource.com/article/19/1/open-source-databases

作者:Sam Bocetta 选题:lujun9972 译者:HankChow 校对:wxy

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

一块硬盘可以被划分成一个或多个逻辑磁盘,我们将其称作分区。我们对硬盘进行的划分信息被储存于建立在扇区 0 的分区表(MBR 或 GPT)中。

Linux 需要至少一个分区来当作根文件系统,所以我们不能在没有分区的情况下安装 Linux 系统。当我们创建一个分区时,我们必须将它格式化为一个适合的文件系统,否则我们就没办法往里面储存文件了。

要在 Linux 中完成分区的相关工作,我们需要一些工具。Linux 下有很多可用的相关工具,我们曾介绍过 Parted 命令。不过,今天我们的主角是 fdisk

人人都喜欢用 fdisk,它是 Linux 下管理磁盘分区的最佳利器之一。它可以操作最大 2TB 的分区。大量 Linux 管理员都喜欢使用这个工具,因为当下 LVM 和 SAN 的原因,并没有多少人会用到 2TB 以上的分区。并且这个工具被世界上许多的基础设施所使用。如果你还是想创建比 2TB 更大的分区,请使用 parted 命令 或 cfdisk 命令。

对磁盘进行分区和创建文件系统是 Linux 管理员的日常。如果你在许多不同的环境中工作,你一定每天都会重复几次这项操作。

Linux 内核是如何理解硬盘的?

作为人类,我们可以很轻松地理解一些事情;但是电脑就不是这样了,它们需要合适的命名才能理解这些。

在 Linux 中,外围设备都位于 /dev 挂载点,内核通过以下的方式理解硬盘:

  • /dev/hdX[a-z]: IDE 硬盘被命名为 hdX
  • /dev/sdX[a-z]: SCSI 硬盘被命名为 sdX
  • /dev/xdX[a-z]: XT 硬盘被命名为 xdX
  • /dev/vdX[a-z]: 虚拟硬盘被命名为 vdX
  • /dev/fdN: 软盘被命名为 fdN
  • /dev/scdN or /dev/srN: CD-ROM 被命名为 /dev/scdN/dev/srN

什么是 fdisk 命令?

fdisk 的意思是 固定磁盘 Fixed Disk 格式化磁盘 Format Disk ,它是命令行下允许用户对分区进行查看、创建、调整大小、删除、移动和复制的工具。它支持 MBR、Sun、SGI、BSD 分区表,但是它不支持 GUID 分区表(GPT)。它不是为操作大分区设计的。

fdisk 允许我们在每块硬盘上创建最多四个主分区。它们中的其中一个可以作为扩展分区,并下设多个逻辑分区。1-4 扇区作为主分区被保留,逻辑分区从扇区 5 开始。

如何在 Linux 下安装 fdisk?

fdisk 作为核心组件内置于 Linux 中,所以你不必手动安装它。

如何用 fdisk 列出可用磁盘?

在执行操作之前,我们必须知道的是哪些磁盘被加入了系统。要想列出所有可用的磁盘,请执行下文的命令。这个命令将会列出磁盘名称、分区数量、分区表类型、磁盘识别代号、分区 ID 和分区类型。

$ sudo fdisk -l
Disk /dev/sda: 30 GiB, 32212254720 bytes, 62914560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xeab59449

Device     Boot    Start      End  Sectors Size Id Type
/dev/sda1  *    20973568 62914559 41940992  20G 83 Linux


Disk /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/sdd: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/sde: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

如何使用 fdisk 列出特定分区信息?

如果你希望查看指定分区的信息,请使用以下命令:

$ sudo fdisk -l /dev/sda
Disk /dev/sda: 30 GiB, 32212254720 bytes, 62914560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xeab59449

Device     Boot    Start      End  Sectors Size Id Type
/dev/sda1  *    20973568 62914559 41940992  20G 83 Linux

如何列出 fdisk 所有的可用操作?

fdisk 中敲击 m,它便会列出所有可用操作:

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xe944b373.

Command (m for help): m

Help:

  DOS (MBR)
   a   toggle a bootable flag
   b   edit nested BSD disklabel
   c   toggle the dos compatibility flag

  Generic
   d   delete a partition
   F   list free unpartitioned space
   l   list known partition types
   n   add a new partition
   p   print the partition table
   t   change a partition type
   v   verify the partition table
   i   print information about a partition

  Misc
   m   print this menu
   u   change display/entry units
   x   extra functionality (experts only)

  Script
   I   load disk layout from sfdisk script file
   O   dump disk layout to sfdisk script file

  Save & Exit
   w   write table to disk and exit
   q   quit without saving changes

  Create a new label
   g   create a new empty GPT partition table
   G   create a new empty SGI (IRIX) partition table
   o   create a new empty DOS partition table
   s   create a new empty Sun partition table

如何使用 fdisk 列出分区类型?

fdisk 中敲击 l,它便会列出所有可用分区的类型:

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x9ffd00db.

Command (m for help): l

 0  Empty           24  NEC DOS         81  Minix / old Lin bf  Solaris        
 1  FAT12           27  Hidden NTFS Win 82  Linux swap / So c1  DRDOS/sec (FAT-
 2  XENIX root      39  Plan 9          83  Linux           c4  DRDOS/sec (FAT-
 3  XENIX usr       3c  PartitionMagic  84  OS/2 hidden or  c6  DRDOS/sec (FAT-
 4  FAT16 <32M      40  Venix 80286     85  Linux extended  c7  Syrinx         
 5  Extended        41  PPC PReP Boot   86  NTFS volume set da  Non-FS data    
 6  FAT16           42  SFS             87  NTFS volume set db  CP/M / CTOS / .
 7  HPFS/NTFS/exFAT 4d  QNX4.x          88  Linux plaintext de  Dell Utility   
 8  AIX             4e  QNX4.x 2nd part 8e  Linux LVM       df  BootIt         
 9  AIX bootable    4f  QNX4.x 3rd part 93  Amoeba          e1  DOS access     
 a  OS/2 Boot Manag 50  OnTrack DM      94  Amoeba BBT      e3  DOS R/O        
 b  W95 FAT32       51  OnTrack DM6 Aux 9f  BSD/OS          e4  SpeedStor      
 c  W95 FAT32 (LBA) 52  CP/M            a0  IBM Thinkpad hi ea  Rufus alignment
 e  W95 FAT16 (LBA) 53  OnTrack DM6 Aux a5  FreeBSD         eb  BeOS fs        
 f  W95 Ext'd (LBA) 54  OnTrackDM6      a6  OpenBSD         ee  GPT            
10  OPUS            55  EZ-Drive        a7  NeXTSTEP        ef  EFI (FAT-12/16/
11  Hidden FAT12    56  Golden Bow      a8  Darwin UFS      f0  Linux/PA-RISC b
12  Compaq diagnost 5c  Priam Edisk     a9  NetBSD          f1  SpeedStor      
14  Hidden FAT16 <3 61  SpeedStor       ab  Darwin boot     f4  SpeedStor      
16  Hidden FAT16    63  GNU HURD or Sys af  HFS / HFS+      f2  DOS secondary  
17  Hidden HPFS/NTF 64  Novell Netware  b7  BSDI fs         fb  VMware VMFS    
18  AST SmartSleep  65  Novell Netware  b8  BSDI swap       fc  VMware VMKCORE 
1b  Hidden W95 FAT3 70  DiskSecure Mult bb  Boot Wizard hid fd  Linux raid auto
1c  Hidden W95 FAT3 75  PC/IX           bc  Acronis FAT32 L fe  LANstep        
1e  Hidden W95 FAT1 80  Old Minix       be  Solaris boot    ff  BBT

如何使用 fdisk 创建一个磁盘分区?

如果你希望新建磁盘分区,请参考下面的步骤。比如我希望在 /dev/sdc 中新建四个分区(三个主分区和一个扩展分区),只需要执行下文的命令。

首先,请在操作 “First sector” 的时候先按下回车,然后在 “Last sector” 中输入你希望创建分区的大小(可以在数字后面加 KB、MB、G 和 TB)。例如,你希望为这个分区扩容 1GB,就应该在 “Last sector” 中输入 +1G。当你创建三个分区之后,fdisk 默认会将分区类型设为扩展分区,如果你希望创建第四个主分区,请输入 p 来替代它的默认值 e

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): Enter

Using default response p.
Partition number (1-4, default 1): Enter
First sector (2048-20971519, default 2048): Enter
Last sector, +sectors or +size{K,M,G,T,P} (2048-20971519, default 20971519): +1G

Created a new partition 1 of type 'Linux' and of size 1 GiB.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8cc8f9e5

Device     Boot Start     End Sectors Size Id Type
/dev/sdc1        2048 2099199 2097152   1G 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

如何使用 fdisk 创建扩展分区?

请注意,创建扩展分区时,你应该使用剩下的所有空间,以便之后在扩展分区下创建逻辑分区。

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition type
   p   primary (3 primary, 0 extended, 1 free)
   e   extended (container for logical partitions)
Select (default e): Enter

Using default response e.
Selected partition 4
First sector (6293504-20971519, default 6293504): Enter
Last sector, +sectors or +size{K,M,G,T,P} (6293504-20971519, default 20971519): Enter

Created a new partition 4 of type 'Extended' and of size 7 GiB.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8cc8f9e5

Device     Boot   Start      End  Sectors Size Id Type
/dev/sdc1          2048  2099199  2097152   1G 83 Linux
/dev/sdc2       2099200  4196351  2097152   1G 83 Linux
/dev/sdc3       4196352  6293503  2097152   1G 83 Linux
/dev/sdc4       6293504 20971519 14678016   7G  5 Extended

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

如何用 fdisk 查看未分配空间?

上文中,我们总共创建了四个分区(三个主分区和一个扩展分区)。在创建逻辑分区之前,扩展分区的容量将会以未分配空间显示。

使用以下命令来显示磁盘上的未分配空间,下面的示例中显示的是 7GB:

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): F
Unpartitioned space /dev/sdc: 7 GiB, 7515144192 bytes, 14678016 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes

  Start      End  Sectors Size
6293504 20971519 14678016   7G

Command (m for help): q

如何使用 fdisk 创建逻辑分区?

创建扩展分区后,请按照之前的步骤创建逻辑分区。在这里,我创建了位于 /dev/sdc51GB 逻辑分区。你可以查看分区表值来确认这点。

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): n
All primary partitions are in use.
Adding logical partition 5
First sector (6295552-20971519, default 6295552): Enter
Last sector, +sectors or +size{K,M,G,T,P} (6295552-20971519, default 20971519): +1G

Created a new partition 5 of type 'Linux' and of size 1 GiB.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8cc8f9e5

Device     Boot   Start      End  Sectors Size Id Type
/dev/sdc1          2048  2099199  2097152   1G 83 Linux
/dev/sdc2       2099200  4196351  2097152   1G 83 Linux
/dev/sdc3       4196352  6293503  2097152   1G 83 Linux
/dev/sdc4       6293504 20971519 14678016   7G  5 Extended
/dev/sdc5       6295552  8392703  2097152   1G 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

如何使用 fdisk 命令删除分区?

如果我们不再使用某个分区,请按照下面的步骤删除它。

请确保你输入了正确的分区号。在这里,我准备删除 /dev/sdc2 分区:

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.30.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): d
Partition number (1-5, default 5): 2

Partition 2 has been deleted.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8cc8f9e5

Device     Boot   Start      End  Sectors Size Id Type
/dev/sdc1          2048  2099199  2097152   1G 83 Linux
/dev/sdc3       4196352  6293503  2097152   1G 83 Linux
/dev/sdc4       6293504 20971519 14678016   7G  5 Extended
/dev/sdc5       6295552  8392703  2097152   1G 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

如何在 Linux 下格式化分区或建立文件系统?

在计算时,文件系统控制了数据的储存方式,并通过 索引节点 Inode Tables 来检索数据。如果没有文件系统,操作系统是无法找到信息储存的位置的。

在此,我准备在 /dev/sdc1 上创建分区。有三种方式创建文件系统:

$ sudo mkfs.ext4 /dev/sdc1
或
$ sudo mkfs -t ext4 /dev/sdc1
或
$ sudo mke2fs /dev/sdc1

mke2fs 1.43.5 (04-Aug-2017)
Creating filesystem with 262144 4k blocks and 65536 inodes
Filesystem UUID: c0a99b51-2b61-4f6a-b960-eb60915faab0
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

当你在分区上建立文件系统时,以下重要信息会同时被创建:

  • Filesystem UUID: UUID 代表了通用且独一无二的识别符,UUID 在 Linux 中通常用来识别设备。它 128 位长的数字代表了 32 个十六进制数。
  • Superblock: 超级块储存了文件系统的元数据。如果某个文件系统的超级块被破坏,我们就无法挂载它了(也就是说无法访问其中的文件了)。
  • Inode: Inode 是类 Unix 系统中文件系统的数据结构,它储存了所有除名称以外的文件信息和数据。
  • Journal: 日志式文件系统包含了用来修复电脑意外关机产生下错误信息的日志。

如何在 Linux 中挂载分区?

在你创建完分区和文件系统之后,我们需要挂载它们以便使用。我们需要创建一个挂载点来挂载分区,使用 mkdir 来创建一个挂载点。

$ sudo mkdir -p /mnt/2g-new

如果你希望进行临时挂载,请使用下面的命令。在计算机重启之后,你会丢失这个挂载点。

$ sudo mount /dev/sdc1 /mnt/2g-new

如果你希望永久挂载某个分区,请将分区详情加入 fstab 文件。我们既可以输入设备名称,也可以输入 UUID。

使用设备名称来进行永久挂载:

# vi /etc/fstab

/dev/sdc1 /mnt/2g-new ext4 defaults 0 0

使用 UUID 来进行永久挂载(请使用 blkid 来获取 UUID):

$ sudo blkid
/dev/sdc1: UUID="d17e3c31-e2c9-4f11-809c-94a549bc43b7" TYPE="ext2" PARTUUID="8cc8f9e5-01"
/dev/sda1: UUID="d92fa769-e00f-4fd7-b6ed-ecf7224af7fa" TYPE="ext4" PARTUUID="eab59449-01"
/dev/sdc3: UUID="ca307aa4-0866-49b1-8184-004025789e63" TYPE="ext4" PARTUUID="8cc8f9e5-03"
/dev/sdc5: PARTUUID="8cc8f9e5-05"

# vi /etc/fstab

UUID=d17e3c31-e2c9-4f11-809c-94a549bc43b7 /mnt/2g-new ext4 defaults 0 0

使用 df 命令亦可:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            969M     0  969M   0% /dev
tmpfs           200M  7.0M  193M   4% /run
/dev/sda1        20G   16G  3.0G  85% /
tmpfs           997M     0  997M   0% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           997M     0  997M   0% /sys/fs/cgroup
tmpfs           200M   28K  200M   1% /run/user/121
tmpfs           200M   25M  176M  13% /run/user/1000
/dev/sdc1      1008M  1.3M  956M   1% /mnt/2g-new

via: https://www.2daygeek.com/linux-fdisk-command-to-manage-disk-partitions/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:zhs852 校对:wxy

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

如果你知道包名称,那么你可以直接安装所需的包。

在某些情况下,如果你不知道确切的包名称或者你想搜索某些包,那么你可以在发行版的包管理器的帮助下轻松搜索该包。搜索会自动包括已安装和可用的包。结果的格式取决于选项。如果你的查询没有输出任何信息,那么意味着没有匹配条件的包。这可以通过发行版的包管理器的各种选项来完成。我已经在本文中添加了所有可能的选项,你可以选择最好的和最合适你的选项。

或者,我们可以通过 whohas 命令实现这一点。它会从所有的主流发行版(例如 Debian、Ubuntu、 Fedora 等)中搜索,而不仅仅是你自己的系统发行版。

建议阅读:

如何在 Debian/Ubuntu 中搜索一个包

我们可以使用 aptapt-cacheaptitude 包管理器在基于 Debian 的发行版上查找给定的包。我为这个包管理器中包括了大量的选项。

我们可以在基于 Debian 的系统中使用三种方式完成此操作。

  • apt 命令
  • apt-cache 命令
  • aptitude 命令

如何使用 apt 命令搜索一个包

APT 代表 高级包管理工具 Advanced Packaging Tool (APT),它取代了 apt-get。它有功能丰富的命令行工具,包括所有功能包含在一个命令(apt)里,包括 apt-cacheapt-searchdpkgapt-cdromapt-configapt-key 等,还有其他几个独特的功能。

APT 是一个强大的命令行工具,它可以访问 libapt-pkg 底层库的所有特性,它可以用于安装、下载、删除、搜索和管理以及查询包的信息,另外它还包含一些较少使用的与包管理相关的命令行实用程序。

$ apt -q list nano vlc
Listing...
nano/artful,now 2.8.6-3 amd64 [installed]
vlc/artful 2.2.6-6 amd64

或者,我们可以使用以下格式搜索指定的包。

$ apt search ^vlc
Sorting... Done
Full Text Search... Done
vlc/artful 2.2.6-6 amd64
  multimedia player and streamer

vlc-bin/artful 2.2.6-6 amd64
  binaries from VLC

vlc-data/artful,artful 2.2.6-6 all
  Common data for VLC

vlc-l10n/artful,artful 2.2.6-6 all
  Translations for VLC

vlc-plugin-access-extra/artful 2.2.6-6 amd64
  multimedia player and streamer (extra access plugins)

vlc-plugin-base/artful 2.2.6-6 amd64
  multimedia player and streamer (base plugins)

如何使用 apt-cache 命令搜索一个包

apt-cache 会在 APT 的包缓存上执行各种操作。它会显示有关指定包的信息。apt-cache 不会改变系统的状态,但提供了从包的元数据中搜索和生成有趣输出的操作。

$ apt-cache search nano | grep ^nano
nano - small, friendly text editor inspired by Pico
nano-tiny - small, friendly text editor inspired by Pico - tiny build
nanoblogger - Small weblog engine for the command line
nanoblogger-extra - Nanoblogger plugins
nanoc - static site generator written in Ruby
nanoc-doc - static site generator written in Ruby - documentation
nanomsg-utils - nanomsg utilities
nanopolish - consensus caller for nanopore sequencing data

或者,我们可以使用以下格式搜索指定的包。

$ apt-cache policy vlc
vlc:
  Installed: (none)
  Candidate: 2.2.6-6
  Version table:
     2.2.6-6 500
        500 http://in.archive.ubuntu.com/ubuntu artful/universe amd64 Packages

或者,我们可以使用以下格式搜索给定的包。

$ apt-cache pkgnames vlc
vlc-bin
vlc-plugin-video-output
vlc-plugin-sdl
vlc-plugin-svg
vlc-plugin-samba
vlc-plugin-fluidsynth
vlc-plugin-qt
vlc-plugin-skins2
vlc-plugin-visualization
vlc-l10n
vlc-plugin-notify
vlc-plugin-zvbi
vlc-plugin-vlsub
vlc-plugin-jack
vlc-plugin-access-extra
vlc
vlc-data
vlc-plugin-video-splitter
vlc-plugin-base

如何使用 aptitude 命令搜索一个包

aptitude 是一个基于文本的 Debian GNU/Linux 软件包系统的命令行界面。它允许用户查看包列表,并执行包管理任务,例如安装、升级和删除包,它可以从可视化界面或命令行执行操作。

$ aptitude search ^vlc
p   vlc                                                                                               - multimedia player and streamer                                                                             
p   vlc:i386                                                                                          - multimedia player and streamer                                                                             
p   vlc-bin                                                                                           - binaries from VLC                                                                                          
p   vlc-bin:i386                                                                                      - binaries from VLC                                                                                          
p   vlc-data                                                                                          - Common data for VLC                                                                                        
v   vlc-data:i386                                                                                     -                                                                                                            
p   vlc-l10n                                                                                          - Translations for VLC                                                                                       
v   vlc-l10n:i386                                                                                     -                                                                                                            
p   vlc-plugin-access-extra                                                                           - multimedia player and streamer (extra access plugins)                                                      
p   vlc-plugin-access-extra:i386                                                                      - multimedia player and streamer (extra access plugins)                                                      
p   vlc-plugin-base                                                                                   - multimedia player and streamer (base plugins)                                                              
p   vlc-plugin-base:i386                                                                              - multimedia player and streamer (base plugins)                                                              
p   vlc-plugin-fluidsynth                                                                             - FluidSynth plugin for VLC                                                                                  
p   vlc-plugin-fluidsynth:i386                                                                        - FluidSynth plugin for VLC                                                                                  
p   vlc-plugin-jack                                                                                   - Jack audio plugins for VLC                                                                                 
p   vlc-plugin-jack:i386                                                                              - Jack audio plugins for VLC                                                                                 
p   vlc-plugin-notify                                                                                 - LibNotify plugin for VLC                                                                                   
p   vlc-plugin-notify:i386                                                                            - LibNotify plugin for VLC                                                                                   
p   vlc-plugin-qt                                                                                     - multimedia player and streamer (Qt plugin)                                                                 
p   vlc-plugin-qt:i386                                                                                - multimedia player and streamer (Qt plugin)                                                                 
p   vlc-plugin-samba                                                                                  - Samba plugin for VLC                                                                                       
p   vlc-plugin-samba:i386                                                                             - Samba plugin for VLC                                                                                       
p   vlc-plugin-sdl                                                                                    - SDL video and audio output plugin for VLC                                                                  
p   vlc-plugin-sdl:i386                                                                               - SDL video and audio output plugin for VLC                                                                  
p   vlc-plugin-skins2                                                                                 - multimedia player and streamer (Skins2 plugin)                                                             
p   vlc-plugin-skins2:i386                                                                            - multimedia player and streamer (Skins2 plugin)                                                             
p   vlc-plugin-svg                                                                                    - SVG plugin for VLC                                                                                         
p   vlc-plugin-svg:i386                                                                               - SVG plugin for VLC                                                                                         
p   vlc-plugin-video-output                                                                           - multimedia player and streamer (video output plugins)                                                      
p   vlc-plugin-video-output:i386                                                                      - multimedia player and streamer (video output plugins)                                                      
p   vlc-plugin-video-splitter                                                                         - multimedia player and streamer (video splitter plugins)                                                    
p   vlc-plugin-video-splitter:i386                                                                    - multimedia player and streamer (video splitter plugins)                                                    
p   vlc-plugin-visualization                                                                          - multimedia player and streamer (visualization plugins)                                                     
p   vlc-plugin-visualization:i386                                                                     - multimedia player and streamer (visualization plugins)                                                     
p   vlc-plugin-vlsub                                                                                  - VLC extension to download subtitles from opensubtitles.org                                                 
p   vlc-plugin-zvbi                                                                                   - VBI teletext plugin for VLC                                                                                
p   vlc-plugin-zvbi:i386 

如何在 RHEL/CentOS 中搜索一个包

Yum(Yellowdog Updater Modified)是 Linux 操作系统中的包管理器实用程序之一。Yum 命令用于在一些基于 RedHat 的 Linux 发行版上,它用来安装、更新、搜索和删除软件包。

# yum search ftpd
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * base: centos.hyve.com
 * epel: mirrors.coreix.net
 * extras: centos.hyve.com
 * rpmforge: www.mirrorservice.org
 * updates: mirror.sov.uk.goscomb.net
============================================================== N/S Matched: ftpd ===============================================================
nordugrid-arc-gridftpd.x86_64 : ARC gridftp server
pure-ftpd.x86_64 : Lightweight, fast and secure FTP server
vsftpd.x86_64 : Very Secure Ftp Daemon

  Name and summary matches only, use "search all" for everything.

或者,我们可以使用以下命令搜索相同内容。

# yum list ftpd

如何在 Fedora 中搜索一个包

DNF 代表 Dandified yum。我们可以说 DNF 是下一代 yum 包管理器(Yum 的衍生品),它使用 hawkey/libsolv 库作为底层。Aleš Kozumplík 从 Fedora 18 开始开发 DNF,最终在 Fedora 22 中发布。

# dnf search ftpd
Last metadata expiration check performed 0:42:28 ago on Tue Jun  9 22:52:44 2018.
============================== N/S Matched: ftpd ===============================
proftpd-utils.x86_64 : ProFTPD - Additional utilities
pure-ftpd-selinux.x86_64 : SELinux support for Pure-FTPD
proftpd-devel.i686 : ProFTPD - Tools and header files for developers
proftpd-devel.x86_64 : ProFTPD - Tools and header files for developers
proftpd-ldap.x86_64 : Module to add LDAP support to the ProFTPD FTP server
proftpd-mysql.x86_64 : Module to add MySQL support to the ProFTPD FTP server
proftpd-postgresql.x86_64 : Module to add PostgreSQL support to the ProFTPD FTP
                          : server
vsftpd.x86_64 : Very Secure Ftp Daemon
proftpd.x86_64 : Flexible, stable and highly-configurable FTP server
owfs-ftpd.x86_64 : FTP daemon providing access to 1-Wire networks
perl-ftpd.noarch : Secure, extensible and configurable Perl FTP server
pure-ftpd.x86_64 : Lightweight, fast and secure FTP server
pyftpdlib.noarch : Python FTP server library
nordugrid-arc-gridftpd.x86_64 : ARC gridftp server

或者,我们可以使用以下命令搜索相同的内容。

# dnf list proftpd
Failed to synchronize cache for repo 'heikoada-terminix', disabling.
Last metadata expiration check: 0:08:02 ago on Tue 26 Jun 2018 04:30:05 PM IST.
Available Packages
proftpd.x86_64

如何在 Arch Linux 中搜索一个包

pacman 代表包管理实用程序(pacman)。它是一个用于安装、构建、删除和管理 Arch Linux 软件包的命令行实用程序。pacman 使用 libalpm(Arch Linux Package Management(ALPM)库)作为底层来执行所有操作。

在本例中,我将要搜索 chromium 包。

# pacman -Ss chromium
extra/chromium 48.0.2564.116-1
    The open-source project behind Google Chrome, an attempt at creating a safer, faster, and more stable browser
extra/qt5-webengine 5.5.1-9 (qt qt5)
    Provides support for web applications using the Chromium browser project
community/chromium-bsu 0.9.15.1-2
    A fast paced top scrolling shooter
community/chromium-chromevox latest-1
    Causes the Chromium web browser to automatically install and update the ChromeVox screen reader extention. Note: This
    package does not contain the extension code.
community/fcitx-mozc 2.17.2313.102-1
    Fcitx Module of A Japanese Input Method for Chromium OS, Windows, Mac and Linux (the Open Source Edition of Google Japanese
    Input)

默认情况下,-s 选项内置 ERE(扩展正则表达式)会导致很多不需要的结果。使用以下格式会仅匹配包名称。

# pacman -Ss '^chromium-'

pkgfile 是一个用于在 Arch Linux 官方仓库的包中搜索文件的工具。

# pkgfile chromium

如何在 openSUSE 中搜索一个包

Zypper 是 SUSE 和 openSUSE 发行版的命令行包管理器。它用于安装、更新、搜索和删除包以及管理仓库,执行各种查询等。Zypper 命令行对接到 ZYpp 系统管理库(libzypp)。

# zypper search ftp
or
# zypper se ftp
Loading repository data...
Reading installed packages...
S | Name           | Summary                                 | Type   
--+----------------+-----------------------------------------+--------
  | proftpd        | Highly configurable GPL-licensed FTP -> | package
  | proftpd-devel  | Development files for ProFTPD           | package
  | proftpd-doc    | Documentation for ProFTPD               | package
  | proftpd-lang   | Languages for package proftpd           | package
  | proftpd-ldap   | LDAP Module for ProFTPD                 | package
  | proftpd-mysql  | MySQL Module for ProFTPD                | package
  | proftpd-pgsql  | PostgreSQL Module for ProFTPD           | package
  | proftpd-radius | Radius Module for ProFTPD               | package
  | proftpd-sqlite | SQLite Module for ProFTPD               | package
  | pure-ftpd      | A Lightweight, Fast, and Secure FTP S-> | package
  | vsftpd         | Very Secure FTP Daemon - Written from-> | package

如何使用 whohas 命令搜索一个包

whohas 命令是一个智能工具,从所有主流发行版中搜索指定包,如 Debian、Ubuntu、Gentoo、Arch、AUR、Mandriva、Fedora、Fink、FreeBSD 和 NetBSD。

$ whohas nano
Mandriva        nano-debug                         2.3.1-1mdv2010.2.x                                           http://sophie.zarb.org/rpms/0b33dc73bca710749ad14bbc3a67e15a
Mandriva        nano-debug                         2.2.4-1mdv2010.1.i                                           http://sophie.zarb.org/rpms/d9dfb2567681e09287b27e7ac6cdbc05
Mandriva        nano-debug                         2.2.4-1mdv2010.1.x                                           http://sophie.zarb.org/rpms/3299516dbc1538cd27a876895f45aee4
Mandriva        nano                               2.3.1-1mdv2010.2.x                                           http://sophie.zarb.org/rpms/98421c894ee30a27d9bd578264625220
Mandriva        nano                               2.3.1-1mdv2010.2.i                                           http://sophie.zarb.org/rpms/cea07b5ef9aa05bac262fc7844dbd223
Mandriva        nano                               2.2.4-1mdv2010.1.s                                           http://sophie.zarb.org/rpms/d61f9341b8981e80424c39c3951067fa
Mandriva        spring-mod-nanoblobs               0.65-2mdv2010.0.sr                                           http://sophie.zarb.org/rpms/74bb369d4cbb4c8cfe6f6028e8562460
Mandriva        nanoxml-lite                       2.2.3-4.1.4mdv2010                                           http://sophie.zarb.org/rpms/287a4c37bc2a39c0f277b0020df47502
Mandriva        nanoxml-manual-lite                2.2.3-4.1.4mdv2010                                           http://sophie.zarb.org/rpms/17dc4f638e5e9964038d4d26c53cc9c6
Mandriva        nanoxml-manual                     2.2.3-4.1.4mdv2010                                           http://sophie.zarb.org/rpms/a1b5092cd01fc8bb78a0f3ca9b90370b
Gentoo      nano                                   9999                                                         http://packages.gentoo.org/package/app-editors/nano 
Gentoo      nano                                   9999                                                         http://packages.gentoo.org/package/app-editors/nano 
Gentoo      nano                                   2.9.8                                                        http://packages.gentoo.org/package/app-editors/nano 
Gentoo      nano                                   2.9.7

如果你希望只从当前发行版仓库中搜索指定包,使用以下格式:

$ whohas -d Ubuntu vlc
Ubuntu      vlc                                    2.1.6-0ubuntu14.04 1M              all                       http://packages.ubuntu.com/trusty/vlc
Ubuntu      vlc                                    2.1.6-0ubuntu14.04 1M              all                       http://packages.ubuntu.com/trusty-updates/vlc
Ubuntu      vlc                                    2.2.2-5ubuntu0.16. 1M              all                       http://packages.ubuntu.com/xenial/vlc
Ubuntu      vlc                                    2.2.2-5ubuntu0.16. 1M              all                       http://packages.ubuntu.com/xenial-updates/vlc
Ubuntu      vlc                                    2.2.6-6            40K             all                       http://packages.ubuntu.com/artful/vlc
Ubuntu      vlc                                    3.0.1-3build1      32K             all                       http://packages.ubuntu.com/bionic/vlc
Ubuntu      vlc                                    3.0.2-0ubuntu0.1   32K             all                       http://packages.ubuntu.com/bionic-updates/vlc
Ubuntu      vlc                                    3.0.3-1            33K             all                       http://packages.ubuntu.com/cosmic/vlc
Ubuntu      browser-plugin-vlc                     2.0.6-2            55K             all                       http://packages.ubuntu.com/trusty/browser-plugin-vlc
Ubuntu      browser-plugin-vlc                     2.0.6-4            47K             all                       http://packages.ubuntu.com/xenial/browser-plugin-vlc
Ubuntu      browser-plugin-vlc                     2.0.6-4            47K             all                       http://packages.ubuntu.com/artful/browser-plugin-vlc
Ubuntu      browser-plugin-vlc                     2.0.6-4            47K             all                       http://packages.ubuntu.com/bionic/browser-plugin-vlc
Ubuntu      browser-plugin-vlc                     2.0.6-4            47K             all                       http://packages.ubuntu.com/cosmic/browser-plugin-vlc
Ubuntu      libvlc-bin                             2.2.6-6            27K             all                       http://packages.ubuntu.com/artful/libvlc-bin
Ubuntu      libvlc-bin                             3.0.1-3build1      17K             all                       http://packages.ubuntu.com/bionic/libvlc-bin
Ubuntu      libvlc-bin                             3.0.2-0ubuntu0.1   17K             all

via: https://www.2daygeek.com/how-to-search-if-a-package-is-available-on-your-linux-distribution-or-not/

作者:Prakash Subramanian 选题:lujun9972 译者:MjSeven 校对:wxy

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