2018年2月

我最近在 docker-library/php 仓库中关闭了大量问题,最老的(并且是最长的)讨论之一是关于安装编译扩展的依赖关系,我写了一个中等篇幅的评论解释了我如何用常规的方式为我想要的软件进行 Docker 化的。

我要在这里复制大部分的评论内容,或许扩展一点点,以便有一个更好的/更干净的链接!

我第一步是编写 Dockerfile 的原始版本:下载源码,运行 ./configure && make 等,清理。然后我尝试构建我的原始版本,并希望在这过程中看到错误消息。(对,真的!)

错误信息通常以 error: could not find "xyz.h"error: libxyz development headers not found 的形式出现。

如果我在 Debian 中构建,我会输入 https://packages.debian.org/file:xyz.h(用错误信息中头文件的名称替换 “xyz.h”),或者在谷歌中搜索像 “xyz.h debian” 这样的东西,找出我需要的包的名称。

如果我在 Alpine 中构建,我将使用 https://pkgs.alpinelinux.org/contents 进行类似的搜索。

“libxyz development headers” 在某种程度上也是一样的,但是根据我的经验,对于这些用 Google 对开发者来说效果更好,因为不同的发行版和项目会以不同的名字来调用这些开发包,所以有时候更难确切的知道哪一个是“正确”的。

当我得到包名后,我将这个包名称添加到我的 Dockerfile 中,清理之后,然后重复操作。最终通常会构建成功。偶尔我发现某些库不在 Debian 或 Alpine 中,或者是不够新的,由此我必须从源码构建它,但这些情况在我的经验中很少见 —— 因人而异。

我还会经常查看 Debian(通过 https://sources.debian.org)或Alpine(通过https://git.alpinelinux.org/cgit/aports/tree)我要编译的软件包源码,特别关注 Build-Depends(如 php7.0=7.0.26-1debian/control 文件)以及/或者 makedepends (如 php7APKBUILD 文件)用于包名线索。

就我个人而言,我觉得这种侦探工作很有趣,也很有收获,但我意识到我可能是一个独特的生物。我偶尔使用的另一个技术是看是否有人已经 Docker 化了我想要的东西,这样我可以直接从他们的 Dockerfile 中知道我需要安装的东西。

对于特定的 PHP 扩展,几乎总是有人已经想出对于这个或那个模块需要的依赖,而我所要做的就是做一些轻量的工作找出它们。

不管怎样,这就是我的方法!希望这个有帮助,玩得愉快!


via: https://tianon.github.io/post/2017/12/26/dockerize-compiled-software.html

作者:Tianon Gravi 译者:geekpi 校对:wxy

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

Facebook、 Gmail、 Twitter 是我们每天都会用的网站(LCTT 译注:才不是呢)。它们的共同点在于都需要你登录进去后才能做进一步的操作。只有你通过认证并登录后才能在 twitter 发推,在 Facebook 上评论,以及在 Gmail上处理电子邮件。

gmail, facebook login page

那么登录的原理是什么?网站是如何认证的?它怎么知道是哪个用户从哪儿登录进来的?下面我们来对这些问题进行一一解答。

用户登录的原理是什么?

每次你在网站的登录页面中输入用户名和密码时,这些信息都会发送到服务器。服务器随后会将你的密码与服务器中的密码进行验证。如果两者不匹配,则你会得到一个错误密码的提示。如果两者匹配,则成功登录。

登录时发生了什么?

登录后,web 服务器会初始化一个 会话 session 并在你的浏览器中设置一个 cookie 变量。该 cookie 变量用于作为新建会话的一个引用。搞晕了?让我们说的再简单一点。

会话的原理是什么?

服务器在用户名和密码都正确的情况下会初始化一个会话。会话的定义很复杂,你可以把它理解为“关系的开始”。

session beginning of a relationship or partnership

认证通过后,服务器就开始跟你展开一段关系了。由于服务器不能象我们人类一样看东西,它会在我们的浏览器中设置一个 cookie 来将我们的关系从其他人与服务器的关系标识出来。

什么是 Cookie?

cookie 是网站在你的浏览器中存储的一小段数据。你应该已经见过他们了。

theitstuff official facebook page cookies

当你登录后,服务器为你创建一段关系或者说一个会话,然后将唯一标识这个会话的会话 id 以 cookie 的形式存储在你的浏览器中。

什么意思?

所有这些东西存在的原因在于识别出你来,这样当你写评论或者发推时,服务器能知道是谁在发评论,是谁在发推。

当你登录后,会产生一个包含会话 id 的 cookie。这样,这个会话 id 就被赋予了那个输入正确用户名和密码的人了。

facebook cookies in web browser

也就是说,会话 id 被赋予给了拥有这个账户的人了。之后,所有在网站上产生的行为,服务器都能通过他们的会话 id 来判断是由谁发起的。

如何让我保持登录状态?

会话有一定的时间限制。这一点与现实生活中不一样,现实生活中的关系可以在不见面的情况下持续很长一段时间,而会话具有时间限制。你必须要不断地通过一些动作来告诉服务器你还在线。否则的话,服务器会关掉这个会话,而你会被登出。

websites keep me logged in option

不过在某些网站上可以启用“保持登录”功能,这样服务器会将另一个唯一变量以 cookie 的形式保存到我们的浏览器中。这个唯一变量会通过与服务器上的变量进行对比来实现自动登录。若有人盗取了这个唯一标识(我们称之为 cookie stealing),他们就能访问你的账户了。

结论

我们讨论了登录系统的工作原理以及网站是如何进行认证的。我们还学到了什么是会话和 cookies,以及它们在登录机制中的作用。

我们希望你们以及理解了用户登录的工作原理,如有疑问,欢迎提问。


via: http://www.theitstuff.com/sessions-cookies-user-login-work

作者:Rishabh Kandari 译者:lujun9972 校对:wxy

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

Vim 是每个 Linux 发行版]中不可或缺的一部分,也是 Linux 用户最常用的工具(当然是基于终端的)。至少,这个说法对我来说是成立的。人们可能会在利用什么工具进行程序设计更好方面产生争议,的确 Vim 可能不是一个好的选择,因为有很多不同的 IDE 或其它类似于 Sublime Text 3,Atom 等使程序设计变得更加容易的成熟的文本编辑器。

我的感想

但我认为,Vim 应该从一开始就以我们想要的方式运作,而其它编辑器让我们按照已经设计好的方式工作,实际上不是我们想要的工作方式。我不会过多地谈论其它编辑器,因为我没有过多地使用过它们(我对 Vim 情有独钟)。

不管怎样,让我们用 Vim 来做一些事情吧,它完全可以胜任。

利用 Vim 进行程序设计

执行代码

考虑一个场景,当我们使用 Vim 设计 C++ 代码并需要编译和运行它时,该怎么做呢。

(a). 我们通过 Ctrl + Z 返回到终端,或者利用 :wq 保存并退出。

(b). 但是任务还没有结束,接下来需要在终端上输入类似于 g++ fileName.cxx 的命令进行编译。

(c). 接下来需要键入 ./a.out 执行它。

为了让我们的 C++ 代码在 shell 中运行,需要做很多事情。但这似乎并不是利用 Vim 操作的方法( Vim 总是倾向于把几乎所有操作方法利用一两个按键实现)。那么,做这些事情的 Vim 的方式究竟是什么?

Vim 方式

Vim 不仅仅是一个文本编辑器,它是一种编辑文本的编程语言。这种帮助我们扩展 Vim 功能的编程语言是 “VimScript”(LCTT 译注: Vim 脚本)。

因此,在 VimScript 的帮助下,我们可以只需一个按键轻松地将编译和运行代码的任务自动化。

create functions in vim .vimrc

以上是在我的 .vimrc 配置文件里创建的一个名为 CPP() 函数的片段。

利用 VimScript 创建函数

在 VimScript 中创建函数的语法非常简单。它以关键字 func 开头,然后是函数名(在 VimScript 中函数名必须以大写字母开头,否则 Vim 将提示错误)。在函数的结尾用关键词 endfunc

在函数的主体中,可以看到 exec 语句,无论您在 exec 关键字之后写什么,都会在 Vim 的命令模式上执行(记住,就是在 Vim 窗口的底部以 : 开始的命令)。现在,传递给 exec 的字符串是(LCTT 译注::!clear && g++ % && ./a.out) -

vim functions commands & symbols

当这个函数被调用时,它首先清除终端屏幕,因此只能看到输出,接着执行 g++ 处理你工作的文件,然后运行由前一步编译而形成的 a.out 文件。

将 ctrl+r 映射为运行 C++ 代码

我将语句 call CPP() 映射到键组合 Ctrl+r,以便我现在可以按 Ctrl+r 来执行我的 C++ 代码,无需手动输入 :call CPP(),然后按 Enter 键。

最终结果

我们终于找到了 Vim 方式的操作方法。现在,你只需按一个(组合)键,你编写的 C++ 代码就输出在你的屏幕上,你不需要键入所有冗长的命令了。这也节省了你的时间。

我们也可以为其他语言实现这类功能。

create function in vim for python

对于Python:您可以按下 Ctrl+e 解释执行您的代码。

create function in vim for java

对于Java:您现在可以按下 Ctrl+j,它将首先编译您的 Java 代码,然后执行您的 Java 类文件并显示输出。

进一步提高

所以,这就是如何在 Vim 中操作的方法。现在,我们来看看如何在 Vim 中实现所有这些。我们可以直接在 Vim 中使用这些代码片段,而另一种方法是使用 Vim 中的自动命令 autocmdautocmd 的优点是这些命令无需用户调用,它们在用户所提供的任何特定条件下自动执行。

我想用 autocmd 实现这个,而不是对每种语言使用不同的映射,执行不同程序设计语言编译出的代码。

autocmd in vimrc

在这里做的是,为所有的定义了执行相应文件类型代码的函数编写了自动命令。

会发生什么?当我打开任何上述提到的文件类型的缓冲区, Vim 会自动将 Ctrl + r 映射到函数调用,而 <CR> 表示回车键,这样就不需要每完成一个独立的任务就按一次回车键了。

为了实现这个功能,您只需将函数片段添加到 .vimrc 文件中,然后将所有这些 autocmd 也一并添加进去。这样,当您下一次打开 Vim 时,Vim 将拥有所有相应的功能来执行所有具有相同绑定键的代码。

总结

就这些了。希望这些能让你更爱 Vim 。我目前正在探究 Vim 中的一些内容,正阅读文档,补充 .vimrc 文件,当我研究出一些成果后我会再次与你分享。

如果你想看一下我现在的 .vimrc 文件,这是我的 Github 账户的链接: MyVimrc

期待你的好评。


via: http://www.linuxandubuntu.com/home/making-vim-even-more-awesome-with-these-cool-features

作者:LINUXANDUBUNTU 译者:stevenzdg988 校对:wxy

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

读者对象

理解 udev 背后的基本概念,学习如何写简单的规则。

要求

  • root 权限

难度

中等

约定

  • # - 要求给定的命令使用 root 权限或者直接以一个 root 用户或者使用 sudo 命令去运行。
  • $ - 要求给定的命令以一个普通的非特权用户运行。

介绍

在 GNU/Linux 系统中,虽然设备的底层支持是在内核层面处理的,但是,它们相关的事件管理是在用户空间中通过 udev 来管理的。确切地说是由 udevd 守护进程来完成的。学习如何去写规则,并应用到发生的这些事件上,将有助于我们修改系统的行为并使它适合我们的需要。

规则如何组织

udev 规则是定义在一个以 .rules 为扩展名的文件中。那些文件主要放在两个位置:/usr/lib/udev/rules.d,这个目录用于存放系统安装的规则;/etc/udev/rules.d/ 这个目录是保留给自定义规则的。

定义那些规则的文件的命名惯例是使用一个数字作为前缀(比如,50-udev-default.rules),并且以它们在目录中的词汇顺序进行处理的。在 /etc/udev/rules.d 中安装的文件,会覆盖安装在系统默认路径中的同名文件。

规则语法

如果你理解了 udev 规则的行为逻辑,它的语法并不复杂。一个规则由两个主要的节构成:match 部分,它使用一系列用逗号分隔的键定义了规则应用的条件,而 action 部分,是当条件满足时,我们执行一些动作。

测试案例

讲解可能的选项的最好方法莫过于配置一个真实的案例,因此,我们去定义一个规则作为演示,当鼠标被连接时禁用触摸板。显然,在该规则定义中提供的属性将反映我的硬件。

我们将在 /etc/udev/rules.d/99-togglemouse.rules 文件中用我们喜欢的文本编辑器来写我们的规则。一条规则定义允许跨多个行,但是,如果是这种情况,必须在一个换行字符之前使用一个反斜线(\)表示行的延续,就和 shell 脚本一样。这是我们的规则:

ACTION=="add" \
, ATTRS{idProduct}=="c52f" \
, ATTRS{idVendor}=="046d" \
, ENV{DISPLAY}=":0" \
, ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority" \
, RUN+="/usr/bin/xinput --disable 16"

我们来分析一下这个规则。

操作符

首先,对已经使用以及将要使用的操作符解释如下:

== 和 != 操作符

== 是相等操作符,而 != 是不等于操作符。通过使用它们,我们可以确认规则上应用的键是否匹配各自的值。

分配操作符 = 和 :=

= 是赋值操作符,是用于为一个键赋值。当我们想要赋值,并且想确保它不会被其它规则所覆盖,我们就需要使用 := 操作符来代替,使用这个操作符分配的值,它就不能被改变。

+= 和 -= 操作符

+=-= 操作符各自用于从一个指定的键定义的值列表中增加或者移除一个值。

我们使用的键

现在,来分析一下在这个规则中我们使用的键。首先,我们有一个 ACTION 键:通过使用它,当在一个设备上发生了特定的事件,我们将指定我们要应用的规则的具体内容。有效的值有 addremove 以及 change

然后,我们使用 ATTRS 关键字去指定一个属性去匹配。我们可以使用 udevadm info 命令去列出一个设备属性,提供它的名字或者 sysfs 路径即可:

udevadm info -ap /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39':
    KERNEL=="input39"
    SUBSYSTEM=="input"
    DRIVER==""
    ATTR{name}=="Logitech USB Receiver"
    ATTR{phys}=="usb-0000:00:1d.0-1.2/input1"
    ATTR{properties}=="0"
    ATTR{uniq}==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010':
    KERNELS=="0003:046D:C52F.0010"
    SUBSYSTEMS=="hid"
    DRIVERS=="hid-generic"
    ATTRS{country}=="00"

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1':
    KERNELS=="2-1.2:1.1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usbhid"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="03"
    ATTRS{bInterfaceNumber}=="01"
    ATTRS{bInterfaceProtocol}=="00"
    ATTRS{bInterfaceSubClass}=="00"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':
    KERNELS=="2-1.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{bMaxPower}=="98mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 2"
    ATTRS{bcdDevice}=="3000"
    ATTRS{bmAttributes}=="a0"
    ATTRS{busnum}=="2"
    ATTRS{configuration}=="RQR30.00_B0009"
    ATTRS{devnum}=="12"
    ATTRS{devpath}=="1.2"
    ATTRS{idProduct}=="c52f"
    ATTRS{idVendor}=="046d"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Logitech"
    ATTRS{maxchild}=="0"
    ATTRS{product}=="USB Receiver"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="removable"
    ATTRS{speed}=="12"
    ATTRS{urbnum}=="1401"
    ATTRS{version}==" 2.00"

    [...]

上面截取了运行这个命令之后的输出的一部分。正如你从它的输出中看到的那样,udevadm 从我们提供的指定路径开始,并且提供了所有父级设备的信息。注意设备的属性都是以单数的形式报告的(比如,KERNEL),而它的父级是以复数形式出现的(比如,KERNELS)。父级信息可以做为规则的一部分,但是同一时间只能有一个父级可以被引用:不同父级设备的属性混合在一起是不能工作的。在上面我们定义的规则中,我们使用了一个父级设备属性:idProductidVendor

在我们的规则中接下来做的事情是,去使用 ENV 关键字:它既可以用于设置也可以用于去匹配环境变量。我们给 DISPLAYXAUTHORITY 分配值。当我们使用 X 服务器程序进行交互去设置一些需要的信息时,这些变量是非常必要的:使用 DISPLAY 变量,我们指定服务器运行在哪个机器上,用的是哪个显示和屏幕;使用 XAUTHORITY 提供了一个文件路径,其包含了 Xorg 认证和授权信息。这个文件一般位于用户的家目录中。

最后,我们使用了 RUN 字:它用于运行外部程序。非常重要:这里没有立即运行,但是一旦所有的规则被解析,将运行各种动作。在这个案例中,我们使用 xinput 实用程序去改变触摸板的状态。我不想解释这里的 xinput 的语法,它超出了本文的范围,只需要注意这个触摸板的 ID 是 16

规则设置完成之后,我们可以通过使用 udevadm test 命令去调试它。这个命令对调试非常有用,它并不真实去运行 RUN 指定的命令:

$ udevadm test --action="add" /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39

我们提供给命令的是使用 --action 选项,以及设备的 sysfs 路径的模拟动作。如果没有报告错误,说明我们的规则运行的很好。要在真实的环境中去使用它,我们需要重新加载规则:

# udevadm control --reload

这个命令将重新加载规则文件,但是,它只对重新加载之后发生的事件有效果。

我们通过创建一个 udev 规则了解了基本的概念和逻辑,这只是 udev 规则中众多的选项和可能的设置中的一小部分。udev 手册页提供了一个详尽的列表,如果你想深入了解,请参考它。


via: https://linuxconfig.org/tutorial-on-how-to-write-basic-udev-rules-in-linux

作者:Egidio Docile 译者:qhwdw 校对:wxy

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

作为一个狂热的互联网人,你在生活中一定遇到过 网络爬虫 Web Crawler 这个词。那么什么是网络爬虫,谁使用网络爬虫?它是如何工作的?让我们在本文中讨论这些。

什么是网络爬虫?

web crawler source code sync

网络爬虫 Web Crawler 也被称为 网络蜘蛛 web-spider 是一个在互联网中访问不同网站的各个页面的互联网软件或者机器人。网络爬虫从这些网页中检索各种信息并将其存储在其记录中。这些抓取工具主要用于从网站收集内容以改善搜索引擎的搜索。

谁使用网络爬虫?

大多数搜索引擎使用爬虫来收集来自公共网站的越来越多的内容,以便它们可以向用户提供更多相关内容。

search engines use web crawlers

许多商业机构使用网络爬虫专门搜索人们的电子邮件地址和电话号码,以便他们可以向你发送促销优惠和其他方案。这基本上是垃圾邮件,但这是大多数公司创建邮件列表的方式。

黑客使用网络爬虫来查找网站文件夹中的所有文件,主要是 HTML 和 Javascript。然后他们尝试通过使用 XSS 来攻击网站。

网络爬虫如何工作?

网络爬虫是一个自动化脚本,它所有行为都是预定义的。爬虫首先从要访问的 URL 的初始列表开始,这些 URL 称为种子。然后它从初始的种子页面确定所有其他页面的超链接。网络爬虫然后将这些网页以 HTML 文档的形式保存,这些 HTML 文档稍后由搜索引擎处理并创建一个索引。

网络爬虫和 SEO

网络爬虫对 SEO,也就是 搜索引擎优化 Search Engine Optimization 有很大的影响。由于许多用户使用 Google,让 Google 爬虫为你的大部分网站建立索引非常重要。这可以通过许多方式来完成,包括不使用重复的内容,并在其他网站上具有尽可能多的反向链接。许多网站被认为是滥用这些技巧,最终被引擎列入黑名单。

robots.txt

robots.txt 是爬虫在抓取你的网站时寻找的一种非常特殊的文件。该文件通常包含有关如何抓取你的网站的信息。一些网站管理员故意不希望他们的网站被索引也可以通过使用 robots.txt 文件阻止爬虫。

总结

爬虫是一个小的软件机器人,可以用来浏览很多网站,并帮助搜索引擎从网上获得最相关的数据。


via: http://www.theitstuff.com/web-crawler-web-crawlers-work

作者:Rishabh Kandari 译者:geekpi 校对:wxy

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

Linux 小白,若对系统管理有兴趣,或想成为资深用户,就需要对命令行有扎实的功底。你需要知道很多命令,其中一个就是 uptime。文本我们会通过一些容易理解的案例来讲解一下这个命令的基本用法。

再开始前有必要说一下,文中的所有案例都在 Ubuntu 16.04 上测试过了。

Linux uptime 命令

望名生义,uptime 命令告诉你系统 启动 up 了(运行了)多长时间。这是语法:

uptime [options]

这个工具的 man 页是这么说的:

uptime会在一行中显示下列信息:当前时间、系统运行了多久时间、当前登录的用户有多少,以及前 1、5 和 15 分钟系统的平均负载。

下面这些问答形式的案例应该会让你对 uptime 命令有更好的了解。

Q1、如何使用 uptime 命令

uptime 的基础用法很简单 —— 只需要输入命令名称然后按下回车就行。

uptime

这是输出:

How to use the uptime command

这里,第一项是当前时间,up 表示系统正在运行,5:53 是系统启动的总时间,最后是系统的 负载 load 信息。若你想深入了解,这里是 uptime man 页中关于最后一项信息的说明:

系统负载是处于 可运行 runnable 不可中断 uninterruptable 状态的进程的平均数。可运行状态的进程要么正在使用 CPU 要么在等待使用 CPU。 不可中断状态的进程则正在等待某些 I/O 访问,例如等待磁盘 IO。

有三个时间间隔的平均值。负载均值的意义根据系统中 CPU 的数量不同而不同,负载为 1 对于一个只有单 CPU 的系统来说意味着负载满了,而对于一个拥有 4 CPU 的系统来说则意味着 75% 的时间里都是空闲的。

Q2、如何以更人性化的格式现实时间

若你只想知道系统运行了多长时间,而且希望以更人性化的格式来显示,那么可以使用 -p 项。

uptime -p

这是输出:

make the tool show up time in pretty format

Q3、如何让 uptime 显示系统启动的日期/时间

你也可以指定 uptme 显示系统开始运行的时间和日期。方法是使用 -s 命令项。

uptime -s

这是输出:

make uptime display date/time since when system is up

Q4、如何获取版本信息和帮助信息

-V 获取版本信息,-h 获取帮助信息。

uptime -V

uptime -h

How to get version information and help

结论

你可以看到,uptime 命令很容易理解也很容易使用。它没有提供很多的功能(命令选项也很少)。这里已经覆盖了它的所有功能了。因此只需要练习一下这些选项你就能在日常工作中使用它了。如果需要的话,你也可以查看它的 man 页


via: https://www.howtoforge.com/linux-uptime-command/

作者:Himanshu Arora 译者:lujun9972 校对:wxy

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