数码文件与文件夹收纳术（以照片为例）

Summary: 这篇文章中我会介绍我是如何避免供应商锁定造成受限于那些临时性的解决方案及数据丢失。相反，我更倾向于使用那些可以让我投入时间和精力打理，并能长久使用的解决方案。

![](/data/attachment/album/201910/05/000950xsxopomsrs55rrb5.jpg)

* 更新 2014-05-14：增加了一些具体实例
* 更新 2015-03-16：根据照片的 GPS 坐标过滤图片
* 更新 2016-08-29：以新的 `filetags --filter` 替换已经过时的 `show-sel.sh` 脚本
* 更新 2017-08-28: geeqier 视频缩略图的邮件评论
* 更新 2018-03-06：增加了 Julian Kahnert 的链接
* 更新 2018-05-06：增加了作者在 2018 Linuxtage Graz 大会上 45 分钟演讲的视频
* 更新 2018-06-05：关于 metadata 的邮件回复
* 更新 2018-07-22：移动文件夹结构的解释到一篇它自己的文章中
* 更新 2019-07-09：关于在文件名中避免使用系谱和字符的邮件回复

每当度假或去哪游玩时我就会化身为一个富有激情的摄影师。所以，过去的几年中我积累了许多的 [JPEG](https://en.wikipedia.org/wiki/Jpeg) 文件。这篇文章中我会介绍我是如何避免 [供应商锁定](http://en.wikipedia.org/wiki/Vendor_lock-in)（LCTT 译注：<ruby> 供应商锁定 <rt>  vendor lock-in </rt></ruby>，原为经济学术语，这里引申为避免过于依赖某一服务平台）造成受限于那些临时性的解决方案及数据丢失。相反，我更倾向于使用那些可以让我**投入时间和精力打理，并能长久使用**的解决方案。

这一（相当长的）攻略 **并不仅仅适用于图像文件**：我将进一步阐述像是文件夹结构、文件的命名规则等等许多领域的事情。因此，这些规范适用于我所能接触到的所有类型的文件。

在我开始传授我的方法之前，我们应该先就我将要介绍方法的达成一个共识，那就是我们是否有相同的需求。如果你对 [raw 图像格式](https://en.wikipedia.org/wiki/Raw_image_format)十分推崇，将照片存储在云端或其他你信赖的地方（对我而言可能不会），那么你可能不会认同这篇文章将要描述的方式了。请根据你的情况来灵活做出选择。

### 我的需求

对于 **将照片（或视频）从我的数码相机中导出到电脑里**，我只需要将 SD 卡插到我的电脑里并调用 `fetch-workflow` 软件。这一步也完成了**图像软件的预处理**以适用于我的文件命名规范（下文会具体论述），同时也可以将图片旋转至正常的方向（而不是横着）。

这些文件将会被存入到我的摄影收藏文件夹 `$HOME/tmp/digicam/`。在这一文件夹中我希望能**遍历我的图像和视频文件**，以便于**整理/删除、重命名、添加/移除标签，以及将一系列相关的文件移动到相应的文件夹中**。

在完成这些以后，我将会**浏览包含图像/电影文件集的文件夹**。在极少数情况下，我希望**在独立的图像处理工具**（比如 [GIMP](http://www.gimp.org/)）中打开一个图像文件。如果仅是为了**旋转 JPEG 文件**，我想找到一个快速的方法，不需要图像处理工具，并且是[以无损的方式](http://petapixel.com/2012/08/14/why-you-should-always-rotate-original-jpeg-photos-losslessly/)旋转 JPEG 图像。

我的数码相机支持用 [GPS](https://en.wikipedia.org/wiki/Gps) 坐标标记图像。因此，我需要一个方法来**对单个文件或一组文件可视化 GPS 坐标**来显示我走过的路径。

我想拥有的另一个好功能是：假设你在威尼斯度假时拍了几百张照片。每一个都很漂亮，所以你每张都舍不得删除。另一方面，你可能想把一组更少的照片送给家里的朋友。而且，在他们嫉妒的爆炸之前，他们可能只希望看到 20 多张照片。因此，我希望能够**定义并显示一组特定的照片子集**。

就独立性和**避免锁定效应**而言，我不想使用那种一旦公司停止产品或服务就无法使用的工具。出于同样的原因，由于我是一个注重隐私的人，**我不想使用任何基于云的服务**。为了让自己对新的可能性保持开放的心态，我不希望只在一个特定的操作系统平台才可行的方案上倾注全部的精力。**基本的东西必须在任何平台上可用**（查看、导航、……），而**全套需求必须可以在 GNU/Linux 上运行**，对我而言，我选择 Debian GNU/Linux。

在我传授当前针对上述大量需求的解决方案之前，我必须解释一下我的一般文件夹结构和文件命名约定，我也使用它来命名数码照片。但首先，你必须认清一个重要的事实：

#### iPhoto、Picasa，诸如此类应被认为是有害的

管理照片集的软件工具确实提供了相当酷的功能。它们提供了一个良好的用户界面，并试图为你提供满足各种需求的舒适的工作流程。

对它们我确实遇到了很多大问题。它们几乎对所有东西都使用专有的存储格式：图像文件、元数据等等。当你打算在几年内换一个不同的软件，这是一个大问题。相信我：总有一天你会因为多种原因而**更换软件**。

如果你现在正打算更换相应的工具，你会意识到 iPhoto 或 Picasa 是分别存储原始图像文件和你对它们所做的所有操作的（旋转图像、向图像文件添加描述/标签、裁剪等等）。如果你不能导出并重新导入到新工具，那么**所有的东西都将永远丢失**。而无损的进行转换和迁移几乎是不可能的。

我不想在一个会锁住我工作的工具上投入任何精力。**我也拒绝把自己绑定在任何专有工具上**。我是一个过来人，希望你们吸取我的经验。

这就是我在文件名中保留时间戳、图像描述或标记的原因。文件名是永久性的，除非我手动更改它们。当我把照片备份或复制到 U 盘或其他操作系统时，它们不会丢失。每个人都能读懂。任何未来的系统都能够处理它们。

### 我的文件命名规范

这里有一个我在 [2018 Linuxtage Graz 大会](https://glt18.linuxtage.at)上做的[演讲](https://glt18-programm.linuxtage.at/events/321.html),其中详细阐述了我的在本文中提到的想法和工作流程。

* [Grazer Linuxtage 2018 - The Advantages of File Name Conventions and Tagging](https://youtu.be/rckSVmYCH90)
* [备份视频托管在 media.CCC.de](https://media.ccc.de/v/GLT18_-_321_-_en_-_g_ap147_004_-_201804281550_-_the_advantages_of_file_name_conventions_and_tagging_-_karl_voit)

我所有的文件都与一个特定的日期或时间有关，根据所采用的 [ISO 8601](https://en.wikipedia.org/wiki/Iso_date) 规范，我采用的是**日期戳**或**时间戳**

带有日期戳和两个标签的示例文件名：`2014-05-09 Budget export for project 42 -- finance company.csv`。

带有时间戳（甚至包括可选秒）和两个标签的示例文件名：`2014-05-09T22.19.58 Susan presenting her new shoes -- family clothing.jpg`。

由于我使用的 ISO 时间戳冒号不适用于 Windows [NTFS 文件系统](https://en.wikipedia.org/wiki/Ntfs)，因此，我用点代替冒号，以便将小时与分钟（以及可选的秒）区别开来。

如果是**持续的一段日期或时间**，我会将两个日期戳或时间戳用两个减号分开：`2014-05-09--2014-05-13 Jazz festival Graz -- folder tourism music.pdf`。

文件名中的时间/日期戳的优点是，除非我手动更改它们，否则它们保持不变。当通过某些不处理这些元数据的软件进行处理时，包含在文件内容本身中的元数据（如 [Exif](https://en.wikipedia.org/wiki/Exif)）往往会丢失。此外，使用这样的日期/时间戳开始的文件名可以确保文件按时间顺序显示，而不是按字母顺序显示。字母表是一种[完全人工的排序顺序](http://www.isisinform.com/reinventing-knowledge-the-medieval-controversy-of-alphabetical-order/)，对于用户定位文件通常不太实用。

当我想将**标签**关联到文件名时，我将它们放在原始文件名和[文件名扩展名](https://en.wikipedia.org/wiki/File_name_extension)之间，中间用空格、两个减号和两端额外的空格分隔 `--`。我的标签是小写的英文单词，不包含空格或特殊字符。有时，我可能会使用 `quantifiedself` 或 `usergenerated` 这样的连接词。我[倾向于选择一般类别](http://karl-voit.at/tagstore/en/papers.shtml)，而不是太过具体的描述标签。我在 Twitter [hashtags](https://en.wikipedia.org/wiki/Hashtag)、文件名、文件夹名、书签、诸如此类的博文等诸如此类地地方重用这些标签。

标签作为文件名的一部分有几个优点。通过使用常用的桌面搜索引擎，你可以在标签的帮助下定位文件。文件名称中的标签不会因为复制到不同的存储介质上而丢失。当系统使用与文件名之外的存储位置（如：元数据数据库、[点文件](https://en.wikipedia.org/wiki/Dot-file)、[备用数据流](https://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29)等）存储元信息通常会发生丢失。

当然，通常在文件和文件夹名称中，**请避免使用特殊字符**、变音符、冒号等。尤其是在不同操作系统平台之间同步文件时。

我的**文件夹名命名约定**与文件的相应规范相同。

注意：由于 [Memacs](https://github.com/novoid/Memacs) 的 [filenametimestamp](https://github.com/novoid/Memacs/blob/master/docs/memacs_filenametimestamps.org) 模块的聪明之处，所有带有日期/时间戳的文件和文件夹都出现在我的 Org 模式的日历（日程）上的同一天/同一时间。这样，我就能很好地了解当天发生了什么，包括我拍的所有照片。

### 我的一般文件夹结构

在本节中，我将描述我的主文件夹中最重要的文件夹。注意：这可能在将来的被移动到一个独立的页面。或许不是。让我们等着瞧 :-) （LCTT 译注：后来这一节已被作者扩展并移动到另外一篇[文章](https://karl-voit.at/folder-hierarchy/)。）

很多东西只有在一定的时间内才会引起人们的兴趣。这些内容包括快速浏览其内容的下载、解压缩文件以检查包含的文件、一些有趣的小内容等等。对于**临时的东西**，我有 `$HOME/tmp/` 子层次结构。新照片放在 `$HOME/tmp/digicam/` 中。我从 CD、DVD 或 USB 记忆棒临时复制的东西放在 `$HOME/tmp/fromcd/` 中。每当软件工具需要用户文件夹层次结构中的临时数据时，我就使用 `$HOME/tmp/Tools/`作为起点。我经常使用的文件夹是 `$HOME/tmp/2del/`：`2del` 的意思是“随时可以删除”。例如，我所有的浏览器都使用这个文件夹作为默认的下载文件夹。如果我需要在机器上腾出空间，我首先查看这个 `2del` 文件夹，用于删除内容。

与上面描述的临时文件相比，我当然也想将文件**保存更长的时间**。这些文件被移动到我的 `$HOME/archive/` 子层次结构中。它有几个子文件夹用于备份、我想保留的 web 下载类、我要存档的二进制文件、可移动媒体（CD、DVD、记忆棒、外部硬盘驱动器）的索引文件，和一个稍后（寻找一个合适的的目标文件夹）存档的文件夹。有时，我太忙或没有耐心的时候将文件妥善整理。是的，那就是我，我甚至有一个名为“现在不要烦我”的文件夹。这对你而言是否很怪？:-)

我的归档中最重要的子层次结构是 `$HOME/archive/events_memories/` 及其子文件夹 `2014/`、`2013/`、`2012/` 等等。正如你可能已经猜到的，每个年份有一个**子文件夹**。其中每个文件中都有单个文件和文件夹。这些文件是根据我在前一节中描述的文件名约定命名的。文件夹名称以 [ISO 8601](https://en.wikipedia.org/wiki/Iso_date) 日期标签 “YYYY-MM-DD” 开头，后面跟着一个具有描述性的名称，如 `$HOME/archive/events_memories/2014/2014-05-08 Business marathon with/`。在这些与日期相关的文件夹中，我保存着各种与特定事件相关的文件：照片、（扫描的）pdf 文件、文本文件等等。

对于**共享数据**，我设置一个 `$HOME/share/` 子层次结构。这是我的 Dropbox 文件夹，我用各种各样的方法（比如 [unison](http://www.cis.upenn.edu/%7Ebcpierce/unison/)）来分享数据。我也在我的设备之间共享数据：家里的 Mac Mini、家里的 GNU/Linux 笔记本、Android 手机，root-server（我的个人云），工作用的 Windows 笔记本。我不想在这里详细说明我的同步设置。如果你想了解相关的设置，可以参考另一篇相关的文章。:-)

在我的 `$HOME/templates_tags/` 子层次结构中，我保存了各种**模板文件**（[LaTeX](https://github.com/novoid/LaTeX-KOMA-template)、脚本、…），插图和**徽标**，等等。

我的 **Org 模式** 文件，主要是保存在 `$HOME/org/`。我练习记忆力，不会解释我有多喜欢 [Emacs/Org 模式](http://orgmode.org/) 以及我从中获益多少。你可能读过或听过我详细描述我用它做的很棒的事情。具体可以在我的博客上查找 [我的 Emacs 标签](http://karl-voit.at/tags/emacs)，在 Twitter 上查找 [hashtag #orgmode](https://twitter.com/search?q%3D%2523orgmode&src%3Dtypd)。

以上就是我最重要的文件夹子层次结构设置方式。

### 我的工作流程

哒哒哒，在你了解了我的文件夹结构和文件名约定之后，下面是我当前的工作流程和工具，我使用它们来满足我前面描述的需求。

请注意，**你必须知道你在做什么**。我这里的示例及文件夹路径和更多**只适用我的机器或我的环境**。**你必须采用相应的**路径、文件名等来满足你的需求!

#### 工作流程：将文件从 SD 卡移动到笔记本电脑、旋转人像图像，并重命名文件

当我想把数据从我的数码相机移到我的 GNU/Linux 笔记本上时，我拿出它的 mini SD 存储卡，把它放在我的笔记本上。然后它会自动挂载在 `/media/digicam` 上。

然后，调用 [getdigicamdata](https://github.com/novoid/getdigicamdata.sh)。它做了如下几件事：它将文件从 SD 卡移动到一个临时文件夹中进行处理。原始文件名会转换为小写字符。所有的人像照片会使用 [jhead](http://www.sentex.net/%3Ccode%3Emwandel/jhead/) 旋转。同样使用 jhead，我从 Exif 头的时间戳中生成文件名称中的时间戳。使用 [date2name](https://github.com/novoid/date2name)，我也将时间戳添加到电影文件中。处理完所有这些文件后，它们将被移动到新的数码相机文件的目标文件夹: `$HOME/tmp/digicam/tmp/`。

#### 工作流程：文件夹索引、查看、重命名、删除图像文件

为了快速浏览我的图像和电影文件，我喜欢使用 GNU/Linux 上的 [geeqie](http://geeqie.sourceforge.net/)。这是一个相当轻量级的图像浏览器，它具有其他文件浏览器所缺少的一大优势：我可以添加通过键盘快捷方式调用的外部脚本/工具。通过这种方式，我可以通过任意外部命令扩展这个图像浏览器的特性。

基本的图像管理功能是内置在 geeqie：浏览我的文件夹层次结构、以窗口模式或全屏查看图像（快捷键 `f`）、重命名文件名、删除文件、显示 Exif 元数据（快捷键 `Ctrl-e`）。

在 OS X 上，我使用 [Xee](http://xee.c3.cx/)。与 geeqie 不同，它不能通过外部命令进行扩展。不过，基本的浏览、查看和重命名功能也是可用的。

#### 工作流程：添加和删除标签

我创建了一个名为 [filetags](https://github.com/novoid/filetag) 的 Python 脚本，用于向单个文件以及一组文件添加和删除标记。

对于数码照片，我使用标签，例如，`specialL` 用于我认为适合桌面背景的风景图片，`specialP` 用于我想展示给其他人的人像照片，`sel` 用于筛选，等等。

##### 使用 geeqie 初始设置 filetags

向 geeqie 添加 `filetags` 是一个手动步骤：“Edit > Preferences > Configure Editors …”，然后创建一个附加条目 `New`。在这里，你可以定义一个新的桌面文件，如下所示:

```
[Desktop Entry]
Name=filetags
GenericName=filetags
Comment=
Exec=/home/vk/src/misc/vk-filetags-interactive-adding-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;
```

*add-tags.desktop*

封装脚本 `vk-filetags-interactive-adding-wrapper-with-gnome-terminal.sh` 是必须的，因为我想要弹出一个新的终端，以便添加标签到我的文件:

```
#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=85x15+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/filetags/filetags.py --interactive "${@}"

#end
```

*vk-filetags-interactive-adding-wrapper-with-gnome-terminal.sh*

在 geeqie 中，你可以在 “Edit > Preferences > Preferences … > Keyboard”。我将 `t` 与 `filetags` 命令相关联。

这个 `filetags` 脚本还能够从单个文件或一组文件中删除标记。它基本上使用与上面相同的方法。唯一的区别是 `filetags` 脚本额外的 `--remove` 参数：

```
[Desktop Entry]
Name=filetags-remove
GenericName=filetags-remove
Comment=
Exec=/home/vk/src/misc/vk-filetags-interactive-removing-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;
```

*remove-tags.desktop*

```
#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=85x15+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/filetags/filetags.py --interactive --remove "${@}"

#end
```

*vk-filetags-interactive-removing-wrapper-with-gnome-terminal.sh*

为了删除标签，我创建了一个键盘快捷方式 `T`。

##### 在 geeqie 中使用 filetags

当我在 geeqie 文件浏览器中浏览图像文件时，我选择要标记的文件（一到多个）并按 `t`。然后，一个小窗口弹出，要求我提供一个或多个标签。用回车确认后，这些标签被添加到文件名中。

删除标签也是一样：选择多个文件，按下 `T`，输入要删除的标签，然后按回车确认。就是这样。几乎没有[给文件添加或删除标签的更简单的方法了](http://karl-voit.at/tagstore/)。

#### 工作流程：改进的使用 appendfilename 重命名文件

##### 不使用 appendfilename

重命名一组大型文件可能是一个冗长乏味的过程。对于 `2014-04-20T17.09.11_p1100386.jpg` 这样的原始文件名，在文件名中添加描述的过程相当烦人。你将按 `Ctrl-r` （重命名）在 geeqie 中打开文件重命名对话框。默认情况下，原始名称（没有文件扩展名的文件名称）被标记。因此，如果不希望删除/覆盖文件名（但要追加），则必须按下光标键 `→`。然后，光标放在基本名称和扩展名之间。输入你的描述（不要忘记以空格字符开始），并用回车进行确认。

##### 在 geeqie 使中用 appendfilename

使用 [appendfilename](https://github.com/novoid/appendfilename)，我的过程得到了简化，可以获得将文本附加到文件名的最佳用户体验：当我在 geeqie 中按下 `a`（附加）时，会弹出一个对话框窗口，询问文本。在回车确认后，输入的文本将放置在时间戳和可选标记之间。

例如，当我在 `2014-04-20T17.09.11_p1100386.jpg` 上按下 `a`，然后键入`Pick-nick in Graz` 时，文件名变为 `2014-04-20T17.09.11_p1100386 Pick-nick in Graz.jpg`。当我再次按下 `a` 并输入 `with Susan` 时，文件名变为 `2014-04-20T17.09.11_p1100386 Pick-nick in Graz with Susan.jpg`。当文件名添加标记时，附加的文本前将附加标记分隔符。

这样，我就不必担心覆盖时间戳或标记。重命名的过程对我来说变得更加有趣!

最好的部分是：当我想要将相同的文本添加到多个选定的文件中时，也可以使用 `appendfilename`。

##### 在 geeqie 中初始设置 appendfilename

添加一个额外的编辑器到 geeqie: “Edit > Preferences > Configure Editors … > New”。然后输入桌面文件定义：

```
[Desktop Entry]
Name=appendfilename
GenericName=appendfilename
Comment=
Exec=/home/vk/src/misc/vk-appendfilename-interactive-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;
```

*appendfilename.desktop*

同样，我也使用了一个封装脚本，它将为我打开一个新的终端：

```
#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=90x5+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/appendfilename/appendfilename.py "${@}"

#end
```

*vk-appendfilename-interactive-wrapper-with-gnome-terminal.sh*

#### 工作流程：播放电影文件

在 GNU/Linux 上，我使用 [mplayer](http://www.mplayerhq.hu) 回放视频文件。由于 geeqie 本身不播放电影文件，所以我必须创建一个设置，以便在 mplayer 中打开电影文件。

##### 在 geeqie 中初始设置 mplayer

我已经使用 [xdg-open](https://wiki.archlinux.org/index.php/xdg-open) 将电影文件扩展名关联到 mplayer。因此，我只需要为 geeqie 创建一个通用的“open”命令，让它使用 `xdg-open` 打开任何文件及其关联的应用程序。

在 geeqie 中，再次访问 “Edit > Preferences > Configure Editors …” 添加“open”的条目：

```
[Desktop Entry]
Name=open
GenericName=open
Comment=
Exec=/usr/bin/xdg-open %F
Icon=
Terminal=true
Type=Application
hidden=false
NOMimeType=*;
MimeType=image/*;video/*
Categories=X-Geeqie;
```

*open.desktop*

当你也将快捷方式 `o` （见上文）与 geeqie 关联时，你就能够打开与其关联的应用程序的视频文件（和其他文件）。

##### 使用 xdg-open 打开电影文件（和其他文件）

在上面的设置过程之后，当你的 geeqie 光标位于文件上方时，你只需按下 `o` 即可。就是如此简洁。

#### 工作流程：在外部图像编辑器中打开

我不太希望能够在 GIMP 中快速编辑图像文件。因此，我添加了一个快捷方式 `g`，并将其与外部编辑器 “GNU Image Manipulation Program (GIMP)” 关联起来，geeqie 已经默认创建了该外部编辑器。

这样，只需按下 `g` 就可以在 GIMP 中打开当前图像。

#### 工作流程：移动到存档文件夹

现在我已经在我的文件名中添加了注释，我想将单个文件移动到 `$HOME/archive/events_memories/2014/`，或者将一组文件移动到这个文件夹中的新文件夹中，如 `$HOME/archive/events_memories/2014/2014-05-08 business marathon after show - party`。

通常的方法是选择一个或多个文件，并用快捷方式 `Ctrl-m` 将它们移动到文件夹中。

何等繁复无趣之至！

因此，我（再次）编写了一个 Python 脚本，它为我完成了这项工作：[move2archive](https://github.com/novoid/move2archive)（简写为：`m2a`），需要一个或多个文件作为命令行参数。然后，出现一个对话框，我可以在其中输入一个可选文件夹名。当我不输入任何东西而是按回车，文件被移动到相应年份的文件夹。当我输入一个类似 `Business-Marathon After-Show-Party` 的文件夹名称时，第一个图像文件的日期戳被附加到该文件夹（`$HOME/archive/events_memories/2014/2014-05-08 Business-Marathon After-Show-Party`），然后创建该文件夹，并移动文件。

再一次，我在 geeqie 中选择一个或多个文件，按 `m`（移动），或者只按回车（没有特殊的子文件夹），或者输入一个描述性文本，这是要创建的子文件夹的名称（可选不带日期戳）。

**没有一个图像管理工具像我的带有 appendfilename 和 move2archive 的 geeqie 一样可以通过快捷键快速且有趣的完成工作。**

##### 在 geeqie 里初始化 m2a 的相关设置

同样，向 geeqie 添加 `m2a` 是一个手动步骤：“Edit > Preferences > Configure Editors …”，然后创建一个附加条目“New”。在这里，你可以定义一个新的桌面文件，如下所示:

```
[Desktop Entry]
Name=move2archive
GenericName=move2archive
Comment=Moving one or more files to my archive folder
Exec=/home/vk/src/misc/vk-m2a-interactive-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;
```

*m2a.desktop*

封装脚本 `vk-m2a-interactive-wrapper-with-gnome-terminal.sh` 是必要的，因为我想要弹出一个新的终端窗口，以便我的文件进入我指定的目标文件夹：

```
#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=157x56+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/m2a/m2a.py --pauseonexit "${@}"

#end
```

*vk-m2a-interactive-wrapper-with-gnome-terminal.sh*

在 geeqie 中，你可以在 “Edit > Preferences > Preferences … > Keyboard” 将 `m` 与 `m2a` 命令相关联。

#### 工作流程：旋转图像（无损）

通常，我的数码相机会自动将人像照片标记为人像照片。然而，在某些特定的情况下（比如从装饰图案上方拍照），我的相机会出错。在那些**罕见的情况下**，我必须手动修正方向。

你必须知道，JPEG 文件格式是一种有损格式，应该只用于照片，而不是计算机生成的东西，如屏幕截图或图表。以傻瓜方式旋转 JPEG 图像文件通常会解压/可视化图像文件、旋转生成新的图像，然后重新编码结果。这将导致生成的图像[比原始图像质量差得多](http://petapixel.com/2012/08/14/why-you-should-always-rotate-original-jpeg-photos-losslessly/)。

因此，你应该使用无损方法来旋转 JPEG 图像文件。

再一次，我添加了一个“外部编辑器”到 geeqie：“Edit > Preferences > Configure Editors … > New”。在这里，我添加了两个条目：使用 [exiftran](http://manpages.ubuntu.com/manpages/raring/man1/exiftran.1.html)，一个用于旋转 270 度（即逆时针旋转 90 度），另一个用于旋转 90 度（顺时针旋转 90 度）：

```
[Desktop Entry]
Version=1.0
Type=Application
Name=Losslessly rotate JPEG image counterclockwise

# call the helper script
TryExec=exiftran
Exec=exiftran -p -2 -i -g %f

# Desktop files that are usable only in Geeqie should be marked like this:
Categories=X-Geeqie;
OnlyShowIn=X-Geeqie;

# Show in menu "Edit/Orientation"
X-Geeqie-Menu-Path=EditMenu/OrientationMenu

MimeType=image/jpeg;
```

*rotate-270.desktop*

```
[Desktop Entry]
Version=1.0
Type=Application
Name=Losslessly rotate JPEG image clockwise

# call the helper script
TryExec=exiftran
Exec=exiftran -p -9 -i -g %f

# Desktop files that are usable only in Geeqie should be marked like this:
Categories=X-Geeqie;
OnlyShowIn=X-Geeqie;

# Show in menu "Edit/Orientation"
X-Geeqie-Menu-Path=EditMenu/OrientationMenu

# It can be made verbose
# X-Geeqie-Verbose=true

MimeType=image/jpeg;
```

*rotate-90.desktop*

我创建了 geeqie 快捷键 `[`（逆时针方向）和 `]`（顺时针方向）。

#### 工作流程：可视化 GPS 坐标

我的数码相机有一个 GPS 传感器，它在 JPEG 文件的 Exif 元数据中存储当前的地理位置。位置数据以 [WGS 84](https://en.wikipedia.org/wiki/WGS84#A_new_World_Geodetic_System:_WGS_84) 格式存储，如 `47, 58, 26.73; 16, 23, 55.51`（纬度；经度）。这一方式可读性较差，我期望：要么是地图，要么是位置名称。因此，我向 geeqie 添加了一些功能，这样我就可以在 [OpenStreetMap](http://www.openstreetmap.org/) 上看到单个图像文件的位置: `Edit > Preferences > Configure Editors ... > New`。

```
[Desktop Entry]
Name=vkphotolocation
GenericName=vkphotolocation
Comment=
Exec=/home/vk/src/misc/vkphotolocation.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-gray;image/x-icb;image/x-ico;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-xbitmap;image/x-xpixmap;image/x-pcx;image/svg+xml;image/svg+xml-compressed;image/vnd.wap.wbmp;
```

*photolocation.desktop*

这调用了我的名为 `vkphotolocation.sh` 的封装脚本，它使用 [ExifTool](http://www.sno.phy.queensu.ca/%7Ephil/exiftool/) 以 [Marble](http://userbase.kde.org/Marble/Tracking) 能够读取和可视化的适当格式提取该坐标:

```
#!/bin/sh

IMAGEFILE="${1}"
IMAGEFILEBASENAME=`basename ${IMAGEFILE}`

COORDINATES=`exiftool -c %.6f "${IMAGEFILE}" | awk '/GPS Position/ { print $4 " " $6 }'`

if [ "x${COORDINATES}" = "x" ]; then
 zenity --info --title="${IMAGEFILEBASENAME}" --text="No GPS-location found in the image file."
else
 /usr/bin/marble --latlon "${COORDINATES}" --distance 0.5
fi

#end
```

*vkphotolocation.sh*

映射到键盘快捷键 `G`，我可以快速地得到**单个图像文件的位置的地图定位**。

当我想将多个 JPEG 图像文件的**位置可视化为路径**时，我使用 [GpsPrune](http://activityworkshop.net/software/gpsprune/)。我无法挖掘出 GpsPrune 将一组文件作为命令行参数的方法。正因为如此，我必须手动启动 GpsPrune，用 “File > Add photos”选择一组文件或一个文件夹。

通过这种方式，我可以为每个 JPEG 位置在 OpenStreetMap 地图上获得一个点（如果配置为这样）。通过单击这样一个点，我可以得到相应图像的详细信息。

如果你恰好在国外拍摄照片，可视化 GPS 位置对**在文件名中添加描述**大有帮助!

#### 工作流程：根据 GPS 坐标过滤照片

这并非我的工作流程。为了完整起见，我列出该工作流对应工具的特性。我想做的就是从一大堆图片中寻找那些在一定区域内（范围或点 + 距离）的照片。

到目前为止，我只找到了 [DigiKam](https://en.wikipedia.org/wiki/DigiKam)，它能够[根据矩形区域进行过滤](https://docs.kde.org/development/en/extragear-graphics/digikam/using-kapp.html#idp7659904)。如果你知道其他工具，请将其添加到下面的评论或给我写一封电子邮件。

#### 工作流程：显示给定集合的子集

如上面的需求所述，我希望能够对一个文件夹中的文件定义一个子集，以便将这个小集合呈现给其他人。

工作流程非常简单：我向选择的文件添加一个标记（通过 `t`/`filetags`）。为此，我使用标记 `sel`，它是 “selection” 的缩写。在标记了一组文件之后，我可以按下 `s`，它与一个脚本相关联，该脚本只显示标记为 `sel` 的文件。

当然，这也适用于任何标签或标签组合。因此，用同样的方法，你可以得到一个适当的概述，你的婚礼上的所有照片都标记着“教堂”和“戒指”。

很棒的功能，不是吗?:-)

##### 初始设置 filetags 以根据标签和 geeqie 过滤

你必须定义一个额外的“外部编辑器”，“ Edit > Preferences > Configure Editors … > New”：

```
[Desktop Entry]
Name=filetag-filter
GenericName=filetag-filter
Comment=
Exec=/home/vk/src/misc/vk-filetag-filter-wrapper-with-gnome-terminal.sh
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;
```

*filter-tags.desktop*

再次调用我编写的封装脚本：

```
#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=85x15+330+5 \
 --hide-menubar \
 -x /home/vk/src/filetags/filetags.py --filter

#end
```

*vk-filetag-filter-wrapper-with-gnome-terminal.sh*

带有参数 `--filter` 的 `filetags` 基本上完成的是：用户被要求输入一个或多个标签。然后，当前文件夹中所有匹配的文件都使用[符号链接](https://en.wikipedia.org/wiki/Symbolic_link)链接到 `$HOME/.filetags_tagfilter/`。然后，启动了一个新的 geeqie 实例，显示链接的文件。

在退出这个新的 geeqie 实例之后，你会看到进行选择的旧的 geeqie 实例。

#### 用一个真实的案例来总结

哇哦, 这是一篇很长的博客文章。你可能已经忘了之前的概述。总结一下我在（扩展了标准功能集的） geeqie 中可以做的事情，我有一个很酷的总结：

| 快捷键 | 功能 |
| --- | --- |
| `m` | 移到归档（m2a） |
| `o` | 打开（针对非图像文件） |
| `a` | 在文件名里添加字段 |
| `t` | 文件标签（添加） |
| `T` | 文件标签（删除） |
| `s` | 文件标签（排序） |
| `g` | gimp |
| `G` | 显示 GPS 信息 |
| `[` | 无损的逆时针旋转 |
| `]` | 无损的顺时针旋转 |
| `Ctrl-e` | EXIF 图像信息 |
| `f` | 全屏显示 |

文件名（包括它的路径）的部分及我用来操作该部分的相应工具：

```
 /this/is/a/folder/2014-04-20T17.09 Picknick in Graz -- food graz.jpg
 [ move2archive  ] [  date2name   ] [appendfilename] [ filetags ]
```

在实践中，我按照以下步骤将照片从相机保存到存档：我将 SD 存储卡放入计算机的 SD 读卡器中。然后我运行 [getdigicamdata.sh](https://github.com/novoid/getdigicamdata.sh)。完成之后，我在 geeqie 中打开 `$HOME/tmp/digicam/tmp/`。我浏览了一下照片，把那些不成功的删除了。如果有一个图像的方向错误，我用 `[` 或 `]` 纠正它。

在第二步中，我向我认为值得评论的文件添加描述 （`a`）。每当我想添加标签时，我也这样做：我快速地标记所有应该共享相同标签的文件（`Ctrl + 鼠标点击`），并使用 [filetags](https://github.com/novoid/filetag)（`t`）进行标记。

要合并来自给定事件的文件，我选中相应的文件，将它们移动到年度归档文件夹中的 `event-folder`，并通过在 [move2archive](https://github.com/novoid/move2archive)（`m`）中键入事件描述，其余的（非特殊的文件夹）无需声明事件描述由 `move2archive` （`m`）直接移动到年度归档中。

结束我的工作流程，我删除了 SD 卡上的所有文件，把它从操作系统上弹出，然后把它放回我的数码相机里。

以上。

因为这种工作流程几乎不需要任何开销，所以评论、标记和归档照片不再是一项乏味的工作。

### 最后

所以，这是一个详细描述我关于照片和电影的工作流程的叙述。你可能已经发现了我可能感兴趣的其他东西。所以请不要犹豫，请使用下面的链接留下评论或电子邮件。

我也希望得到反馈，如果我的工作流程适用于你。并且，如果你已经发布了你的工作流程或者找到了其他人工作流程的描述，也请留下评论!

及时行乐，莫让错误的工具或低效的方法浪费了我们的人生！

### 其他工具

阅读关于[本文中关于 gThumb 的部分](http://karl-voit.at/2017/02/19/gthumb)。

当你觉得你以上文中所叙述的符合你的需求时，请根据相关的建议来选择对应的工具。

---

via: <http://karl-voit.at/managing-digital-photographs/>

作者：[Karl Voit](http://karl-voit.at) 译者：[qfzy1233](https://github.com/qfzy1233) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Fedora 31 将放弃 32 位 i686 支持

Summary: Fedora 31 中丢弃了 32 位 i686 内核及其可启动镜像。

Fedora 31 中丢弃了 32 位 i686 内核及其可启动镜像。

![](/data/attachment/album/201910/05/111602sofdze38czrnf58z.jpg)

Fedora 31 中[丢弃了](https://fedoraproject.org/wiki/Changes/Stop_Building_i686_Kernels) 32 位 i686 内核及其可启动镜像。虽然可能有一些用户仍然拥有无法与 64 位 x86\_64 内核一起使用的硬件，但数量很少。本文为你提供了这次更改背后的整个事情，以及在 Fedora 31 中仍然可以找到的 32 位元素。

### 发生了什么？

i686 架构实质上从 [Fedora 27 版本](https://fedoramagazine.org/announcing-fedora-27/)就进入了社区支持阶段（LCTT 译注：不再由官方支持）。不幸的是，社区中没有足够的成员愿意做维护该体系结构的工作。不过请放心，Fedora 不会删除所有 32 位软件包，仍在构建许多 i686 软件包，以确保诸如 multilib、wine 和 Steam 之类的东西可以继续工作。

尽管该存储库不再构建和镜像输出，但存在一个 koji i686 存储库，该库可与 mock 一起使用以构建 32 位程序包，并且可以在紧要关头安装不属于 x86\_64 multilib 存储库的 32 位版本。当然，维护人员希望这样做解决有限的使用场景。只是需要运行一个 32 位应用程序的用户应该可以在 64 位系统上使用 multilib 来运行。

### 如果你要运行 32 位应用需要做什么？

如果你仍在运行 32 位 i686 系统，则会在 Fedora 30 生命周期中继续收到受支持的 Fedora 更新。直到大约 2020 年 5 月或 6 月。到那时，如果硬件支持，你可以将其重新安装为 64 位 x86\_64，或者如果可能的话，将其替换为支持 64 位的硬件。

社区中有一个用户已经成功地从 32 位 Fedora “升级” 到了 64 位 x86 Fedora。虽然这不是预期或受支持的升级路径，但应该也可行。该项目希望可以为具有 64 位功能的硬件的用户提供一些文档，以在 Fedora 30 使用寿命终止之前说明该升级过程。

如果有 64 位的 CPU，但由于内存不足而运行 32 位 Fedora，请尝试[备用桌面流派](https://spins.fedoraproject.org)之一。LXDE 和其他产品在内存受限的环境中往往表现良好。对于仅在旧的可以扔掉的 32 位硬件上运行简单服务器的用户，请考虑使用较新的 ARM 板之一。在许多情况下，仅节能一项就可以支付新硬件的费用。如果以上皆不可行，[CentOS 7](https://centos.org) 提供了一个 32 位镜像，并对该平台提供长期支持。

### 安全与你

尽管有些用户可能会在生命周期结束后继续运行旧版本的 Fedora，但强烈建议不要这样做。人们不断研究软件的安全问题。通常，他们发现这些问题已经存在多年了。

一旦 Fedora 维护人员知道了此类问题，他们通常会为它们打补丁，并为支持的发行版提供更新，而不会给使用寿命已终止的发行版提供。当然，一旦这些漏洞公开，就会有人尝试利用它们。如果你在生命周期结束时运行了较旧的发行版，则安全风险会随着时间的推移而增加，从而使你的系统面临不断增长的风险。

---

via: <https://fedoramagazine.org/in-fedora-31-32-bit-i686-is-86ed/>

作者：[Justin Forbes](https://fedoramagazine.org/author/jforbes/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


给 Zsh 添加主题和插件

Summary: 通过 Oh My Zsh 安装的主题和插件来扩展 Zsh 的功能。

通过 Oh My Zsh 安装的主题和插件来扩展 Zsh 的功能。

>
> 通过 Oh My Zsh 安装的主题和插件来扩展 Zsh 的功能。
>
>
>

![](/data/attachment/album/201910/05/120457r49mk2l9oelv94bi.jpg)

在我的[前文](/article-11378-1.html)中，我向大家展示了如何安装并使用 [Z-Shell](/article-11378-1.html) (Zsh)。对于某些用户来说，Zsh 最令人激动的是它可以安装主题。Zsh 安装主题非常容易，一方面是因为有非常活跃的社区为 Z-Shell 设计主题，另一方面是因为有 [Oh My Zsh](https://ohmyz.sh/) 这个项目。这使得安装主题变得轻而易举。

主题的变化可能会立刻吸引你的注意力，因此如果你安装了 Zsh 并且将默认的 Shell 替换为 Zsh 时，你可能不喜欢 Shell 默认主题的样子，那么你可以立即更换 Oh My Zsh 自带的 100 多个主题。Oh My Zsh 不仅拥有大量精美的主题，同时还有数以百计的扩展 Zsh 功能的插件。

### 安装 Oh My Zsh

Oh My Zsh 的[官网](https://ohmyz.sh/)建议你使用一个脚本在有网络的情况下来安装这个包。尽管 Oh My Zsh 项目几乎是可以令人信服的，但是盲目地在你的电脑上运行一个脚本这是一个糟糕的建议。如果你想运行这个脚本，你可以把它下载下来，看一下它实现了什么功能，在你确信你已经了解了它的所作所为之后，你就可以运行它了。

如果你下载了脚本并且阅读了它，你就会发现安装过程仅仅只有三步：

#### 1、克隆 oh-my-zsh

第一步，克隆 oh-my-zsh 库到 `~/.oh-my-zsh` 目录：

```
% git clone http://github.com/robbyrussell/oh-my-zsh ~/.oh-my-zsh
```

#### 2、切换配置文件

下一步，备份你已有的 `.zshrc` 文件，然后将 oh-my-zsh 自带的配置文件移动到这个地方。这两步操作可以一步完成，只需要你的 `mv` 命令支持 `-b` 这个选项。

```
% mv -b \
~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc
```

#### 3、编辑配置文件

默认情况下，Oh My Zsh 自带的配置文件是非常简陋的。如果你想将你自己的 `~/.zshrc` 文件合并到 `.oh-my-zsh` 的配置文件中。你可以使用 [cat](https://opensource.com/article/19/2/getting-started-cat-command) 命令将你的旧的配置文件添加到新文件的末尾。

```
% cat ~/.zshrc~ >> ~/.zshrc
```

看一下默认的配置文件以及它提供的一些选项。用你最喜欢的编辑器打开 `~/.zshrc` 文件。这个文件有非常良好的注释。这是了解它的一个非常好的方法。

例如，你可以更改 `.oh-my-zsh` 目录的位置。在安装的时候，它默认是位于你的家目录。但是，根据 [Free Desktop](http://freedesktop.org) 所定义的现代 Linux 规范。这个目录应当放置于 `~/.local/share` 。你可以在配置文件中进行修改。如下所示：

```
# Path to your oh-my-zsh installation.
export ZSH=$HOME/.local/share/oh-my-zsh
```

然后将 .oh-my-zsh 目录移动到你新配置的目录下：

```
% mv ~/.oh-my-zsh $HOME/.local/share/oh-my-zsh
```

如果你使用的是 MacOS，这个目录可能会有点含糊不清，但是最合适的位置可能是在 `$HOME/Library/Application\ Support`。

### 重新启动 Zsh

编辑配置文件之后，你必须重新启动你的 Shell。在这之前，你必须确定你的任何操作都已正确完成。例如，在你修改了 `.oh-my-zsh` 目录的路径之后。不要忘记将目录移动到新的位置。如果你不想重新启动你的 Shell。你可以使用 `source` 命令来使你的配置文件生效。

```
% source ~/.zshrc
➜  .oh-my-zsh git:(master) ✗
```

你可以忽略任何丢失更新文件的警告；他们将会在重启的时候再次进行解析。

### 更换你的主题

安装好 oh-my-zsh 之后。你可以将你的 Zsh 的主题设置为 `robbyrussell`，这是一个该项目维护者的主题。这个主题的更改是非常小的，仅仅是改变了提示符的颜色。

你可以通过列出 `.oh-my-zsh` 目录下的所有文件来查看所有安装的主题：

```
➜  .oh-my-zsh git:(master) ✗ ls ~/.local/share/oh-my-zsh/themes
3den.zsh-theme
adben.zsh-theme
af-magic.zsh-theme
afowler.zsh-theme
agnoster.zsh-theme
[...]
```

想在切换主题之前查看一下它的样子，你可以查看 Oh My Zsh 的 [wiki](https://github.com/robbyrussell/oh-my-zsh/wiki/Themes) 页面。要查看更多主题，可以查看 [外部主题](https://github.com/robbyrussell/oh-my-zsh/wiki/External-themes) wiki 页面。

大部分的主题是非常易于安装和使用的，仅仅需要改变 `.zshrc` 文件中的配置选项然后重新载入配置文件。

```
➜ ~ sed -i 's/_THEME=\"robbyrussel\"/_THEME=\"linuxonly\"/g' ~/.zshrc
➜ ~ source ~/.zshrc
seth@darkstar:pts/0->/home/skenlon (0) ➜
```

其他的主题可能需要一些额外的配置。例如，为了使用 `agnoster` 主题，你必须先安装 Powerline 字体。这是一个开源字体，如果你使用 Linux 操作系统的话，这个字体很可能在你的软件库中存在。使用下面的命令安装这个字体：

```
➜ ~ sudo dnf install powerline-fonts
```

在配置文件中更改你的主题：

```
➜ ~ sed -i 's/_THEME=\"linuxonly\"/_THEME=\"agnoster\"/g' ~/.zshrc
```

重新启动你的 Sehll（一个简单的 `source` 命令并不会起作用）。一旦重启，你就可以看到新的主题：

![agnoster theme](/data/attachment/album/201910/05/120539pnofailixuohniou.jpg "agnoster theme")

### 安装插件

Oh My Zsh 有超过 200 的插件，你可以在 `.oh-my-zsh/plugins` 中看到它们。每一个扩展目录下都有一个 `README` 文件解释了这个插件的作用。

一些插件相当简单。例如，`dnf`、`ubuntu`、`brew` 和 `macports` 插件仅仅是为了简化与 DNF、Apt、Homebres 和 MacPorts 的交互操作而定义的一些别名。

而其他的一些插件则较为复杂，`git` 插件默认是被激活使用的。当你的目录是一个 git 仓库的时候，这个扩展就会更新你的 Shell 提示符，以显示当前的分支和是否有未合并的更改。

为了激活这个扩展，你可以将这个扩展添加到你的配置文件 `~/.zshrc` 中。例如，你可以添加 `dnf` 和 `pass` 插件，按照如下的方式更改：

```
plugins=(git dnf pass)
```

保存修改，重新启动你的 Shell。

```
% source ~/.zshrc
```

这个扩展现在就可以使用了。你可以通过使用 `dnf` 提供的别名来测试一下：

```
% dnfs fop
====== Name Exactly Matched: fop ======
fop.noarch : XSL-driven print formatter
```

不同的插件做不同的事，因此你可以一次安装一两个插件来帮你学习新的特性和功能。

### 兼容性

一些 Oh My Zsh 插件具有通用性。如果你看到一个插件声称它可以与 Bash 兼容，那么它就可以在你自己的 Bash 中使用。另一些插件需要 Zsh 提供的特定功能。因此，它们并不是所有都能工作。但是你可以添加一些其他的插件，例如 `dnf`、`ubuntu`、`firewalld`，以及其他的一些插件。你可以使用 `source` 使你的选择生效。例如：

```
if [ -d $HOME/.local/share/oh-my-zsh/plugins ]; then
        source $HOME/.local/share/oh-my-zsh/plugins/dnf/dnf.plugin.zsh
fi
```

### 选择或者不选择 Zsh

Z-shell 的内置功能和它由社区贡献的扩展功能都非常强大。你可以把它当成你的主 Shell 使用，你也可以在你休闲娱乐的时候尝试一下。这取决于你的爱好。

什么是你最喜爱的主题和扩展可以在下方的评论告诉我们！

---

via: <https://opensource.com/article/19/9/adding-plugins-zsh>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[amwps290](https://github.com/amwps290) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在 21 世纪该怎样编译 Linux 内核

Summary: 也许你并不需要编译 Linux 内核，但你能通过这篇教程快速上手。

也许你并不需要编译 Linux 内核，但你能通过这篇教程快速上手。

>
> 也许你并不需要编译 Linux 内核，但你能通过这篇教程快速上手。
>
>
>

![](/data/attachment/album/201910/06/113927vrs6rurljyuza8cy.jpg)

在计算机世界里，<ruby> 内核 <rt>  kernel </rt></ruby>是处理硬件与一般系统之间通信的<ruby> 低阶软件 <rt>  low-level software </rt></ruby>。除过一些烧录进计算机主板的初始固件，当你启动计算机时，内核让系统意识到它有一个硬盘驱动器、屏幕、键盘以及网卡。分配给每个部件相等时间（或多或少）使得图像、音频、文件系统和网络可以流畅甚至并行地运行。

然而，对于硬件的需求是源源不断的，随着发布的硬件越多，内核就必须纳入更多代码来保证那些硬件正常工作。得到具体的数字很困难，但是 Linux 内核无疑是硬件兼容性方面的顶级内核之一。Linux 操作着无数的计算机和移动电话、工业用途和爱好者使用的板级嵌入式系统（SoC）、RAID 卡、缝纫机等等。

回到 20 世纪（甚至是 21 世纪初期），对于 Linux 用户来说，在刚买到新的硬件后就需要下载最新的内核代码并编译安装才能使用这是不可理喻的。而现在你也很难见到 Linux 用户为了好玩而编译内核或通过高度专业化定制的硬件的方式赚钱。现在，通常已经不需要再编译 Linux 内核了。

这里列出了一些原因以及快速编译内核的教程。

### 更新当前的内核

无论你买了配备新显卡或 Wifi 芯片集的新品牌电脑还是给家里配备一个新的打印机，你的操作系统（称为 GNU+Linux 或 Linux，它也是该内核的名字）需要一个驱动程序来打开新部件（显卡、芯片集、打印机和其他任何东西）的信道。有时候当你插入某些新的设备时而你的电脑表示发现了它，这具有一定的欺骗性。别被骗到了，有时候那就够了，但更多的情况是你的操作系统仅仅是使用了通用的协议检测到安装了新的设备。

例如，你的计算机也许能够鉴别出新的网络打印机，但有时候那仅仅是因为打印机的网卡被设计成为了获得 DHCP 地址而在网络上标识自己。它并不意味着你的计算机知道如何发送文档给打印机进行打印。事实上，你可以认为计算机甚至不“知道”那台设备是一个打印机。它也许仅仅是显示网络有个设备在一个特定的地址上，并且该设备以一系列字符 “p-r-i-n-t-e-r” 标识自己而已。人类语言的便利性对于计算机毫无意义。计算机需要的是一个驱动程序。

内核开发者、硬件制造商、技术支持和爱好者都知道新的硬件会不断地发布。它们大多数都会贡献驱动程序，直接提交给内核开发团队以包含在 Linux 中。例如，英伟达显卡驱动程序通常都会写入 [Nouveau](https://nouveau.freedesktop.org/wiki/) 内核模块中，并且因为英伟达显卡很常用，它的代码都包含在任一个日常使用的发行版内核中（例如当下载 [Fedora](http://fedoraproject.org) 或 [Ubuntu](http://ubuntu.com) 得到的内核）。英伟达也有不常用的地方，例如嵌入式系统中 Nouveau 模块通常被移除。对其他设备来说也有类似的模块：打印机得益于 [Foomatic](https://wiki.linuxfoundation.org/openprinting/database/foomatic) 和 [CUPS](https://www.cups.org/)，无线网卡有 [b43、ath9k、wl](https://wireless.wiki.kernel.org/en/users/drivers) 模块等等。

发行版往往会在它们 Linux 内核的构建中包含尽可能多合理的驱动程序，因为他们想让你在接入新设备时不用安装驱动程序能够立即使用。对于大多数情况来说就是这样的，尤其是现在很多设备厂商都在资助自己售卖硬件的 Linux 驱动程序开发，并且直接将这些驱动程序提交给内核团队以用在通常的发行版上。

有时候，或许你正在运行六个月之前安装的内核，并配备了上周刚刚上市令人兴奋的新设备。在这种情况下，你的内核也许没有那款设备的驱动程序。好消息是经常会出现那款设备的驱动程序已经存在于最近版本的内核中，意味着你只要更新运行的内核就可以了。

通常，这些都是通过安装包管理软件完成的。例如在 RHEL、CentOS 和 Fedora 上：

```
$ sudo dnf update kernel
```

在 Debian 和 Ubuntu 上，首先获取你当前内核的版本：

```
$ uname -r
4.4.186
```

搜索新的版本：

```
$ sudo apt update
$ sudo apt search linux-image
```

安装找到的最新版本。在这个例子中，最新的版本是 5.2.4：

```
$ sudo apt install linux-image-5.2.4
```

内核更新后，你必须 [reboot](https://opensource.com/article/19/7/reboot-linux) （除非你使用 kpatch 或 kgraft）。这时，如果你需要的设备驱动程序包含在最新的内核中，你的硬件就会正常工作。

### 安装内核模块

有时候一个发行版没有预计到用户会使用某个设备（或者该设备的驱动程序至少不足以包含在 Linux 内核中）。Linux 对于驱动程序采用模块化方式，因此尽管驱动程序没有编译进内核，但发行版可以推送单独的驱动程序包让内核去加载。尽管有些复杂但是非常有用，尤其是当驱动程序没有包含进内核中而是在引导过程中加载，或是内核中的驱动程序相比模块化的驱动程序过期时。第一个问题可以用 “initrd” 解决（初始化 RAM 磁盘），这一点超出了本文的讨论范围，第二点通过 “kmod” 系统解决。

kmod 系统保证了当内核更新后，所有与之安装的模块化驱动程序也得到更新。如果你手动安装一个驱动程序，你就体验不到 kmod 提供的自动化，因此只要能用 kmod 安装包，就应该选择它。例如，尽管英伟达驱动程序以 Nouveau 模块构建在内核中，但官方的驱动程序仅由英伟达发布。你可以去网站上手动安装英伟达旗下的驱动程序，下载 “.run” 文件，并运行提供的 shell 脚本，但在安装了新的内核之后你必须重复相同的过程，因为没有任何东西告诉包管理软件你手动安装了一个内核驱动程序。英伟达驱动着你的显卡，手动更新英伟达驱动程序通常意味着你需要通过终端来执行更新，因为没有显卡驱动程序将无法显示。

![Nvidia configuration application](/data/attachment/album/201910/06/114010jez62e1zmxf1rpfj.jpg "Nvidia configuration application")

然而，如果你通过 kmod 包安装英伟达驱动程序，更新你的内核也会更新你的英伟达驱动程序。在 Fedora 和相关的发行版中：

```
$ sudo dnf install kmod-nvidia
```

在 Debian 和相关发行版上：

```
$ sudo apt update
$ sudo apt install nvidia-kernel-common nvidia-kernel-dkms nvidia-glx nvidia-xconfig nvidia-settings nvidia-vdpau-driver vdpau-va-driver
```

这仅仅是一个例子，但是如果你真的要安装英伟达驱动程序，你也必须屏蔽掉 Nouveau 驱动程序。参考你使用发行版的文档获取最佳的步骤吧。

### 下载并安装驱动程序

不是所有的东西都包含在内核中，也不是所有的东西都可以作为内核模块使用。在某些情况下，你需要下载一个由供应商编写并绑定好的特殊驱动程序，还有一些情况，你有驱动程序，但是没有配置驱动程序的前端界面。

有两个常见的例子是 HP 打印机和 [Wacom](https://linuxwacom.github.io) 数位板。如果你有一台 HP 打印机，你可能有能够和打印机通信的通用的驱动程序，甚至能够打印出东西。但是通用的驱动程序却不能为特定型号的打印机提供定制化的选项，例如双面打印、校对、纸盒选择等等。[HPLIP](https://developers.hp.com/hp-linux-imaging-and-printing)（HP Linux 成像和打印系统）提供了选项来进行任务管理、调整打印设置、选择可用的纸盒等等。

HPLIP 通常包含在包管理软件中；只要搜索“hplip”就行了。

![HPLIP in action](/data/attachment/album/201910/06/114011gmkdaqop6zsssro6.jpg "HPLIP in action")

同样的，电子艺术家主要使用的数位板 Wacom 的驱动程序通常也包含在内核中，但是例如调整压感和按键功能等设置只能通过默认包含在 GNOME 的图形控制面板访问。但也可以作为 KDE 上额外的程序包“kde-config-tablet”来访问。

这里也有几个类似的个别例子，例如内核中没有驱动程序，但是以 RPM 或 DEB 文件提供了可供下载并且通过包管理软件安装的 kmod 版本的驱动程序。

### 打上补丁并编译你的内核

即使在 21 世纪的未来主义乌托邦里，仍有厂商不够了解开源，没有提供可安装的驱动程序。有时候，一些公司为驱动程序提供开源代码，而需要你下载代码、修补内核、编译并手动安装。

这种发布方式和在 kmod 系统之外安装打包的驱动程序拥有同样的缺点：对内核的更新会破坏驱动程序，因为每次更换新的内核时都必须手动将其重新集成到内核中。

令人高兴的是，这种事情变得少见了，因为 Linux 内核团队在呼吁公司们与他们交流方面做得很好，并且公司们最终接受了开源不会很快消失的事实。但仍有新奇的或高度专业的设备仅提供了内核补丁。

官方上，对于你如何编译内核以使包管理器参与到升级系统如此重要的部分中，发行版有特定的习惯。这里有太多的包管理器，所以无法一一涵盖。举一个例子，当你使用 Fedora 上的工具例如 `rpmdev` 或 `build-essential`，Debian 上的 `devscripts`。

首先，像通常那样，找到你正在运行内核的版本：

```
$ uname -r
```

在大多数情况下，如果你还没有升级过内核那么可以试试升级一下内核。搞定之后，也许你的问题就会在最新发布的内核中解决。如果你尝试后发现不起作用，那么你应该下载正在运行内核的源码。大多数发行版提供了特定的命令来完成这件事，但是手动操作的话，可以在 [kernel.org](https://www.kernel.org/) 上找到它的源代码。

你必须下载内核所需的任何补丁。有时候，这些补丁对应具体的内核版本，因此请谨慎选择。

通常，或至少在人们习惯于编译内核的那时，都是拿到源代码并对 `/usr/src/linux` 打上补丁。

解压内核源码并打上需要的补丁：

```
$ cd /usr/src/linux
$ bzip2 --decompress linux-5.2.4.tar.bz2
$ cd  linux-5.2.4
$ bzip2 -d ../patch*bz2
```

补丁文件也许包含如何使用的教程，但通常它们都设计成在内核源码树的顶层可用来执行。

```
$ patch -p1 < patch*example.patch
```

当内核代码打上补丁后，你可以继续使用旧的配置来对打了补丁的内核进行配置。

```
$ make oldconfig
```

`make oldconfig` 命令有两个作用：它继承了当前的内核配置，并且允许你配置补丁带来的新的选项。

你或许需要运行 `make menuconfig` 命令，它启动了一个基于 ncurses 的菜单界面，列出了新的内核所有可能的选项。整个菜单可能看不过来，但是它是以旧的内核配置为基础的，你可以遍历菜单并且禁用掉你没有或不需要的硬件模块。另外，如果你知道自己有一些硬件没有包含在当前的配置中，你可以选择构建它，当作模块或者直接嵌入内核中。理论上，这些并不是必要的，因为你可以猜想，当前的内核运行良好只是缺少了补丁，当使用补丁的时候可能已经激活了所有设备所必要的选项。

下一步，编译内核和它的模块：

```
$ make bzImage
$ make modules
```

这会产生一个叫作 `vmlinuz` 的文件，它是你的可引导内核的压缩版本。保存旧的版本并在 `/boot` 文件夹下替换为新的。

```
$ sudo mv /boot/vmlinuz /boot/vmlinuz.nopatch
$ sudo cat arch/x86_64/boot/bzImage > /boot/vmlinuz
$ sudo mv /boot/System.map /boot/System.map.stock
$ sudo cp System.map /boot/System.map
```

到目前为止，你已经打上了补丁并且编译了内核和它的模块，你安装了内核，但你并没有安装任何模块。那就是最后的步骤：

```
$ sudo make modules_install
```

新的内核已经就位，并且它的模块也已经安装。

最后一步是更新你的引导程序，为了让你的计算机在加载 Linux 内核之前知道它的位置。GRUB 引导程序使这一过程变得相当简单：

```
$ sudo grub2-mkconfig
```

### 现实生活中的编译

当然，现在没有人手动执行这些命令。相反的，参考你的发行版，寻找发行版维护人员使用的开发者工具集修改内核的说明。这些工具集可能会创建一个集成所有补丁的可安装软件包，告诉你的包管理器来升级并更新你的引导程序。

### 内核

操作系统和内核都是玄学，但要理解构成它们的组件并不难。下一次你看到某个技术无法应用在 Linux 上时，深呼吸，调查可用的驱动程序，寻找一条捷径。Linux 比以前简单多了——包括内核。

---

via: <https://opensource.com/article/19/8/linux-kernel-21st-century>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[LuMing](https://github.com/LuuMing) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在 Linux 上记录和重放终端会话活动

Summary: 在某些情况下，我们要检查上一个会话的命令输出，并希望将其与当前会话进行比较。因此在这种情况下，script 命令就变得很方便。

【script】是一个简单实用的命令，与别人交流或者是想保存重要的命令串时候很有用。

通常，Linux 管理员们都使用 `history` 命令来跟踪在先前的会话中执行过哪些命令，但是 `history` 命令的局限性在于它不存储命令的输出。在某些情况下，我们要检查上一个会话的命令输出，并希望将其与当前会话进行比较。除此之外，在某些情况下，我们正在对 Linux 生产环境中的问题进行故障排除，并希望保存所有终端会话活动以供将来参考，因此在这种情况下，`script` 命令就变得很方便。

![](/data/attachment/album/201910/06/122659mmi64z8ryr4z2n8a.jpg)

`script` 是一个命令行工具，用于捕获/记录你的 Linux 服务器终端会话活动，以后可以使用 `scriptreplay` 命令重放记录的会话。在本文中，我们将演示如何安装 `script` 命令行工具以及如何记录 Linux 服务器终端会话活动，然后，我们将看到如何使用 `scriptreplay` 命令来重放记录的会话。

### 安装 script 工具

#### 在 RHEL 7/ CentOS 7 上安装 script 工具

`script` 命令由 RPM 包 `util-linux` 提供，如果你没有在你的 CentOS 7 / RHEL 7 系统上安装它，运行下面的 `yum` 安装它：

```
[root@linuxtechi ~]# yum install util-linux -y
```

#### 在 RHEL 8 / CentOS 8 上安装 script 工具

运行下面的 `dnf` 命令来在 RHEL 8 / CentOS 8 上安装 `script` 工具：

```
[root@linuxtechi ~]# dnf install util-linux -y
```

#### 在基于 Debian 的系统（Ubuntu / Linux Mint）上安装 script 工具

运行下面的 `apt-get` 命令来安装 `script` 工具：

```
root@linuxtechi ~]# apt-get install util-linux -y
```

### 如何使用 script 工具

直接使用 `script` 命令，在终端上键入 `script` 命令，然后按回车，它将开始在名为 `typescript` 的文件中捕获当前的终端会话活动。

```
[root@linuxtechi ~]# script
Script started, file is typescript
[root@linuxtechi ~]#
```

要停止记录会话活动，请键入 `exit` 命令，然后按回车：

```
[root@linuxtechi ~]# exit
exit
Script done, file is typescript
[root@linuxtechi ~]#
```

`script` 命令的语法格式：

```
~] # script {options}  {file_name}
```

能在 `script` 命令中使用的不同选项：

![options-script-command](/data/attachment/album/201910/06/122713o4vvjz6xmxljc4vd.png)

让我们开始通过执行 `script` 命令来记录 Linux 终端会话，然后执行诸如 `w`，`route -n`，`df -h` 和 `free -h`，示例如下所示：

![script-examples-linux-server](/data/attachment/album/201910/06/122715ud9bxq9ovq2b0dqa.jpg)

正如我们在上面看到的，终端会话日志保存在文件 `typescript` 中：

现在使用 `cat` / `vi` 命令查看 `typescript` 文件的内容，

```
[root@linuxtechi ~]# ls -l typescript
-rw-r--r--. 1 root root 1861 Jun 21 00:50 typescript
[root@linuxtechi ~]#
```

![typescript-file-content-linux](/data/attachment/album/201910/06/122716y7f166757hfl56fs.jpg)

以上内容确认了我们在终端上执行的所有命令都已保存在 `typescript` 文件中。

### 在 script 命令中使用定制文件名

假设我们要使用自定义文件名来执行 `script` 命令，可以在 `script` 命令后指定文件名。在下面的示例中，我们使用的文件名为 `session-log-(当前日期时间).txt`。

```
[root@linuxtechi ~]# script sessions-log-$(date +%d-%m-%Y-%T).txt
Script started, file is sessions-log-21-06-2019-01:37:39.txt
[root@linuxtechi ~]#
```

现在运行该命令并输入 `exit`：

```
[root@linuxtechi ~]# exit
exit
Script done, file is sessions-log-21-06-2019-01:37:39.txt
[root@linuxtechi ~]#
```

### 附加命令输出到 script 记录文件

假设 `script` 命令已经将命令输出记录到名为 `session-log.txt` 的文件中，现在我们想将新会话命令的输出附加到该文件中，那么可以在 `script` 命令中使用 `-a` 选项。

```
[root@linuxtechi ~]# script -a sessions-log.txt
Script started, file is sessions-log.txt
[root@linuxtechi ~]# xfs_info /dev/mapper/centos-root
meta-data=/dev/mapper/centos-root isize=512    agcount=4, agsize=2746624 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0 spinodes=0
data     =                       bsize=4096   blocks=10986496, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal               bsize=4096   blocks=5364, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@linuxtechi ~]# exit
exit
Script done, file is sessions-log.txt
[root@linuxtechi ~]#
```

要查看更新的会话记录，使用 `cat session-log.txt` 命令。

### 无需 shell 交互而捕获命令输出到 script 记录文件

假设我们要捕获命令的输出到会话记录文件，那么使用 `-c` 选项，示例如下所示：

```
[root@linuxtechi ~]# script -c "uptime && hostname && date" root-session.txt
Script started, file is root-session.txt
 01:57:40 up  2:30,  3 users,  load average: 0.00, 0.01, 0.05
linuxtechi
Fri Jun 21 01:57:40 EDT 2019
Script done, file is root-session.txt
[root@linuxtechi ~]#
```

### 以静默模式运行 script 命令

要以静默模式运行 `script` 命令，请使用 `-q` 选项，该选项将禁止 `script` 的启动和完成消息，示例如下所示：

```
[root@linuxtechi ~]# script -c "uptime && date" -q root-session.txt
 02:01:10 up  2:33,  3 users,  load average: 0.00, 0.01, 0.05
Fri Jun 21 02:01:10 EDT 2019
[root@linuxtechi ~]#
```

要将时序信息记录到文件中并捕获命令输出到单独的文件中，这可以通过在 `script` 命令中传递时序文件（`-timing`）实现，示例如下所示：

语法格式：

```
~ ]# script -t <timing-file-name>  {file_name}
```

```
[root@linuxtechi ~]# script --timing=timing.txt session.log
Script started, file is session.log
[root@linuxtechi ~]# uptime
 02:27:59 up  3:00,  3 users,  load average: 0.00, 0.01, 0.05
[root@linuxtechi ~]# date
Fri Jun 21 02:28:02 EDT 2019
[root@linuxtechi ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           3.9G        171M        2.0G        8.6M        1.7G        3.3G
Swap:          3.9G          0B        3.9G
[root@linuxtechi ~]# whoami
root
[root@linuxtechi ~]# exit
exit
Script done, file is session.log
[root@linuxtechi ~]#
[root@linuxtechi ~]# ls -l session.log timing.txt
-rw-r--r--. 1 root root 673 Jun 21 02:28 session.log
-rw-r--r--. 1 root root 414 Jun 21 02:28 timing.txt
[root@linuxtechi ~]#
```

### 重放记录的 Linux 终端会话活动

现在，使用 `scriptreplay` 命令重放录制的终端会话活动。

注意：`scriptreplay` 也由 RPM 包 `util-linux` 提供。`scriptreplay` 命令需要时序文件才能工作。

```
[root@linuxtechi ~]# scriptreplay --timing=timing.txt session.log
```

上面命令的输出将如下所示，

![](/data/attachment/album/201910/06/122718q7riaibd8a7rr8r7.gif)

### 记录所有用户的 Linux 终端会话活动

在某些关键业务的 Linux 服务器上，我们希望跟踪所有用户的活动，这可以使用 `script` 命令来完成，将以下内容放在 `/etc/profile` 文件中，

```
[root@linuxtechi ~]# vi /etc/profile
……………………………………………………
if [ "x$SESSION_RECORD" = "x" ]
then
timestamp=$(date +%d-%m-%Y-%T)
session_log=/var/log/session/session.$USER.$$.$timestamp
SESSION_RECORD=started
export SESSION_RECORD
script -t -f -q 2>${session_log}.timing $session_log
exit
fi
……………………………………………………
```

保存文件并退出。

在 `/var/log` 文件夹下创建 `session` 目录：

```
[root@linuxtechi ~]# mkdir /var/log/session
```

给该文件夹指定权限：

```
[root@linuxtechi ~]# chmod 777 /var/log/session/
[root@linuxtechi ~]#
```

现在，验证以上代码是否有效。在我正在使用 `pkumar` 用户的情况下，登录普通用户到 Linux 服务器：

```
~ ] # ssh root@linuxtechi
root@linuxtechi's password:
[root@linuxtechi ~]$ uptime
 04:34:09 up  5:06,  3 users,  load average: 0.00, 0.01, 0.05
[root@linuxtechi ~]$ date
Fri Jun 21 04:34:11 EDT 2019
[root@linuxtechi ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:           3.9G        172M        2.0G        8.6M        1.7G        3.3G
Swap:          3.9G          0B        3.9G
[root@linuxtechi ~]$ id
uid=1001(pkumar) gid=1002(pkumar) groups=1002(pkumar) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@linuxtechi ~]$ whoami
pkumar
[root@linuxtechi ~]$ exit

Login as root and view user’s linux terminal session activity

[root@linuxtechi ~]# cd /var/log/session/
[root@linuxtechi session]# ls -l | grep pkumar
-rw-rw-r--. 1 pkumar pkumar 870 Jun 21 04:34 session.pkumar.19785.21-06-2019-04:34:05
-rw-rw-r--. 1 pkumar pkumar 494 Jun 21 04:34 session.pkumar.19785.21-06-2019-04:34:05.timing
[root@linuxtechi session]#
```

![Session-output-file-linux](/data/attachment/album/201910/06/122719dexuklun2x9kx2lf.jpg)

我们还可以使用 `scriptreplay` 命令来重放用户的终端会话活动：

```
[root@linuxtechi session]# scriptreplay --timing session.pkumar.19785.21-06-2019-04\:34\:05.timing session.pkumar.19785.21-06-2019-04\:34\:05
```

以上就是本教程的全部内容，请在下面的评论部分中分享你的反馈和评论。

---

via: <https://www.linuxtechi.com/record-replay-linux-terminal-sessions-activity/>

作者：[Pradeep Kumar](https://www.linuxtechi.com/author/pradeep/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


通过编写扫雷游戏提高你的 Bash 技巧

>
> 那些令人怀念的经典游戏可是提高编程能力的好素材。今天就让我们仔细探索一番，怎么用 Bash 编写一个扫雷程序。
>
>
>

![](/data/attachment/album/201910/07/115136p51t04j584m4o18z.jpg)

我在编程教学方面不是专家，但当我想更好掌握某一样东西时，会试着找出让自己乐在其中的方法。比方说，当我想在 shell 编程方面更进一步时，我决定用 Bash 编写一个[扫雷](https://en.wikipedia.org/wiki/Minesweeper_(video_game))游戏来加以练习。

如果你是一个有经验的 Bash 程序员，希望在提高技巧的同时乐在其中，那么请跟着我编写一个你的运行在终端中的扫雷游戏。完整代码可以在这个 [GitHub 存储库](https://github.com/abhiTamrakar/playground/tree/master/bash_games)中找到。

### 做好准备

在我编写任何代码之前，我列出了该游戏所必须的几个部分：

1. 显示雷区
2. 创建游戏逻辑
3. 创建判断单元格是否可选的逻辑
4. 记录可用和已查明（已排雷）单元格的个数
5. 创建游戏结束逻辑

### 显示雷区

在扫雷中，游戏界面是一个由 2D 数组（列和行）组成的不透明小方格。每一格下都有可能藏有地雷。玩家的任务就是找到那些不含雷的方格，并且在这一过程中，不能点到地雷。这个 Bash 版本的扫雷使用 10x10 的矩阵，实际逻辑则由一个简单的 Bash 数组来完成。

首先，我先生成了一些随机数字。这将是地雷在雷区里的位置。控制地雷的数量，在开始编写代码之前，这么做会容易一些。实现这一功能的逻辑可以更好，但我这么做，是为了让游戏实现保持简洁，并有改进空间。（我编写这个游戏纯属娱乐，但如果你能将它修改的更好，我也是很乐意的。）

下面这些变量在整个过程中是不变的，声明它们是为了随机生成数字。就像下面的 `a` - `g` 的变量，它们会被用来计算可排除的地雷的值：

```
# 变量
score=0 # 会用来存放游戏分数
# 下面这些变量，用来随机生成可排除地雷的实际值
a="1 10 -10 -1"
b="-1 0 1"
c="0 1"
d="-1 0 1 -2 -3"
e="1 2 20 21 10 0 -10 -20 -23 -2 -1"
f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 -3 -2 -1"
g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7"
#
# 声明
declare -a room  # 声明一个 room 数组，它用来表示雷区的每一格。
```

接下来，我会用列（0-9）和行（a-j）显示出游戏界面，并且使用一个 10x10 矩阵作为雷区。（`M[10][10]` 是一个索引从 0-99，有 100 个值的数组。） 如想了解更多关于 Bash 数组的内容，请阅读这本书[那些关于 Bash 你所不了解的事: Bash 数组简介](https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays)。

创建一个叫 `plough` 的函数，我们先将标题显示出来：两个空行、列头，和一行 `-`，以示意往下是游戏界面:

```
printf '\n\n'
printf '%s' "     a   b   c   d   e   f   g   h   i   j"
printf '\n   %s\n' "-----------------------------------------"
```

然后，我初始化一个计数器变量，叫 `r`，它会用来记录已显示多少横行。注意，稍后在游戏代码中，我们会用同一个变量 `r`，作为我们的数组索引。 在 [Bash for 循环](https://opensource.com/article/19/6/how-write-loop-bash)中，用 `seq` 命令从 0 增加到 9。我用数字（`d%`）占位，来显示行号（`$row`，由 `seq` 定义）：

```
r=0 # 计数器
for row in $(seq 0 9); do
  printf '%d  ' "$row" # 显示 行数 0-9
```

在我们接着往下做之前，让我们看看到现在都做了什么。我们先横着显示 `[a-j]` 然后再将 `[0-9]` 的行号显示出来，我们会用这两个范围，来确定用户排雷的确切位置。

接着，在每行中，插入列，所以是时候写一个新的 `for` 循环了。这一循环管理着每一列，也就是说，实际上是生成游戏界面的每一格。我添加了一些辅助函数，你能在源码中看到它的完整实现。 对每一格来说，我们需要一些让它看起来像地雷的东西，所以我们先用一个点（`.`）来初始化空格。为了实现这一想法，我们用的是一个叫 [`is_null_field`](https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L114-L120) 的自定义函数。 同时，我们需要一个存储每一格具体值的数组，这儿会用到之前已定义的全局数组 [`room`](https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L41) , 并用 [变量 `r`](https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L74)作为索引。随着 `r` 的增加，遍历所有单元格，并随机部署地雷。

```
  for col in $(seq 0 9); do
    ((r+=1))  # 循环完一列行数加一
    is_null_field $r  #  假设这里有个函数，它会检查单元格是否为空，为真，则此单元格初始值为点（.）
    printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" #  最后显示分隔符，注意，${room[$r]} 的第一个值为 '.'，等于其初始值。
  #结束 col 循环
  done
```

最后，为了保持游戏界面整齐好看，我会在每行用一个竖线作为结尾，并在最后结束行循环：

```
printf '%s\n' "|"   # 显示出行分隔符
printf '   %s\n' "-----------------------------------------"
# 结束行循环
done
printf '\n\n'
```

完整的 `plough` 代码如下：

```
plough()
{
  r=0
  printf '\n\n'
  printf '%s' "     a   b   c   d   e   f   g   h   i   j"
  printf '\n   %s\n' "-----------------------------------------"
  for row in $(seq 0 9); do
    printf '%d  ' "$row"
    for col in $(seq 0 9); do
       ((r+=1))
       is_null_field $r
       printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}"
    done
    printf '%s\n' "|"
    printf '   %s\n' "-----------------------------------------"
  done
  printf '\n\n'
}
```

我花了点时间来思考，`is_null_field` 的具体功能是什么。让我们来看看，它到底能做些什么。在最开始，我们需要游戏有一个固定的状态。你可以随便选择个初始值，可以是一个数字或者任意字符。我最后决定，所有单元格的初始值为一个点（`.`），因为我觉得，这样会让游戏界面更好看。下面就是这一函数的完整代码：

```
is_null_field()
{
  local e=$1 # 在数组 room 中，我们已经用过循环变量 'r' 了，这次我们用 'e'
    if [[ -z "${room[$e]}" ]];then
      room[$r]="."  #这里用点（.）来初始化每一个单元格
    fi
}
```

现在，我已经初始化了所有的格子，现在只要用一个很简单的函数就能得出当前游戏中还有多少单元格可以操作：

```
get_free_fields()
{
  free_fields=0    # 初始化变量
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then  # 检查当前单元格是否等于初始值（.），结果为真，则记为空余格子。
      ((free_fields+=1))
    fi
  done
}
```

这是显示出来的游戏界面，`[a-j]` 为列，`[0-9]` 为行。

![Minefield](/data/attachment/album/201910/07/115159fb5z9b3qn11v111q.png "Minefield")

### 创建玩家逻辑

玩家操作背后的逻辑在于，先从 [stdin](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)) 中读取数据作为坐标，然后再找出对应位置实际包含的值。这里用到了 Bash 的[参数扩展](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html)，来设法得到行列数。然后将代表列数的字母传给分支语句，从而得到其对应的列数。为了更好地理解这一过程，可以看看下面这段代码中，变量 `o` 所对应的值。 举个例子，玩家输入了 `c3`，这时 Bash 将其分成两个字符：`c` 和 `3`。为了简单起见，我跳过了如何处理无效输入的部分。

```
  colm=${opt:0:1}  # 得到第一个字符，一个字母
  ro=${opt:1:1}    # 得到第二个字符，一个整数
  case $colm in
    a ) o=1;;      # 最后，通过字母得到对应列数。
    b ) o=2;;
    c ) o=3;;
    d ) o=4;;
    e ) o=5;;
    f ) o=6;;
    g ) o=7;;
    h ) o=8;;
    i ) o=9;;
    j ) o=10;;
  esac
```

下面的代码会计算用户所选单元格实际对应的数字，然后将结果储存在变量中。

这里也用到了很多的 `shuf` 命令，`shuf` 是一个专门用来生成随机序列的 [Linux 命令](https://linux.die.net/man/1/shuf)。`-i` 选项后面需要提供需要打乱的数或者范围，`-n` 选项则规定输出结果最多需要返回几个值。Bash 中，可以在两个圆括号内进行[数学计算](https://www.tldp.org/LDP/abs/html/dblparens.html)，这里我们会多次用到。

还是沿用之前的例子，玩家输入了 `c3`。 接着，它被转化成了 `ro=3` 和 `o=3`。 之后，通过上面的分支语句代码， 将 `c` 转化为对应的整数，带进公式，以得到最终结果 `i` 的值。

```
  i=$(((ro*10)+o))   # 遵循运算规则，算出最终值
  is_free_field $i $(shuf -i 0-5 -n 1)   #  调用自定义函数，判断其指向空/可选择单元格。
```

仔细观察这个计算过程，看看最终结果 `i` 是如何计算出来的：

```
i=$(((ro*10)+o))
i=$(((3*10)+3))=$((30+3))=33
```

最后结果是 33。在我们的游戏界面显示出来，玩家输入坐标指向了第 33 个单元格，也就是在第 3 行（从 0 开始，否则这里变成 4），第 3 列。

### 创建判断单元格是否可选的逻辑

为了找到地雷，在将坐标转化，并找到实际位置之后，程序会检查这一单元格是否可选。如不可选，程序会显示一条警告信息，并要求玩家重新输入坐标。

在这段代码中，单元格是否可选，是由数组里对应的值是否为点（`.`）决定的。如果可选，则重置单元格对应的值，并更新分数。反之，因为其对应值不为点，则设置变量 `not_allowed`。为简单起见，游戏中[警告消息](https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L143-L177)这部分源码，我会留给读者们自己去探索。

```
is_free_field()
{
  local f=$1
  local val=$2
  not_allowed=0
  if [[ "${room[$f]}" = "." ]]; then
    room[$f]=$val
    score=$((score+val))
  else
    not_allowed=1
  fi
}
```

![Extracting mines](/data/attachment/album/201910/07/115200yun3rw2r9b8fjw69.png "Extracting mines")

如输入坐标有效，且对应位置为地雷，如下图所示。玩家输入 `h6`，游戏界面会出现一些随机生成的值。在发现地雷后，这些值会被加入用户得分。

![Extracting mines](/data/attachment/album/201910/07/115203umy7fft9vmfrvfto.png "Extracting mines")

还记得我们开头定义的变量，`a` - `g` 吗，我会用它们来确定随机生成地雷的具体值。所以，根据玩家输入坐标，程序会根据（`m`）中随机生成的数，来生成周围其他单元格的值（如上图所示）。之后将所有值和初始输入坐标相加，最后结果放在 `i`（计算结果如上）中。

请注意下面代码中的 `X`，它是我们唯一的游戏结束标志。我们将它添加到随机列表中。在 `shuf` 命令的魔力下，`X` 可以在任意情况下出现，但如果你足够幸运的话，也可能一直不会出现。

```
m=$(shuf -e a b c d e f g X -n 1)   # 将 X 添加到随机列表中，当 m=X，游戏结束
  if [[ "$m" != "X" ]]; then        # X 将会是我们爆炸地雷（游戏结束）的触发标志
    for limit in ${!m}; do          # !m 代表 m 变量的值
      field=$(shuf -i 0-5 -n 1)     # 然后再次获得一个随机数字
      index=$((i+limit))            # 将 m 中的每一个值和 index 加起来，直到列表结尾
      is_free_field $index $field
    done
```

我想要游戏界面中，所有随机显示出来的单元格，都靠近玩家选择的单元格。

![Extracting mines](/data/attachment/album/201910/07/115204ri4htjh4554yg4gd.png "Extracting mines")

### 记录已选择和可用单元格的个数

这个程序需要记录游戏界面中哪些单元格是可选择的。否则，程序会一直让用户输入数据，即使所有单元格都被选中过。为了实现这一功能，我创建了一个叫 `free_fields` 的变量，初始值为 `0`。用一个 `for` 循环，记录下游戏界面中可选择单元格的数量。 如果单元格所对应的值为点（`.`），则 `free_fields` 加一。

```
get_free_fields()
{
  free_fields=0
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then
      ((free_fields+=1))
    fi
  done
}
```

等下，如果 `free_fields=0` 呢？ 这意味着，玩家已选择过所有单元格。如果想更好理解这一部分，可以看看这里的[源代码](https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L91)。

```
if [[ $free_fields -eq 0 ]]; then   # 这意味着你已选择过所有格子
      printf '\n\n\t%s: %s %d\n\n' "You Win" "you scored" "$score"
      exit 0
fi
```

### 创建游戏结束逻辑

对于游戏结束这种情况，我们这里使用了一些很[巧妙的技巧](https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L131-L141)，将结果在屏幕中央显示出来。我把这部分留给读者朋友们自己去探索。

```
if [[ "$m" = "X" ]]; then
    g=0                      # 为了在参数扩展中使用它
    room[$i]=X               # 覆盖此位置原有的值，并将其赋值为X
    for j in {42..49}; do    # 在游戏界面中央，
      out="gameover"
      k=${out:$g:1}          # 在每一格中显示一个字母
      room[$j]=${k^^}
      ((g+=1))
    done
fi
```

最后，我们显示出玩家最关心的两行。

```
if [[ "$m" = "X" ]]; then
      printf '\n\n\t%s: %s %d\n' "GAMEOVER" "you scored" "$score"
      printf '\n\n\t%s\n\n' "You were just $free_fields mines away."
      exit 0
fi
```

![Minecraft Gameover](/data/attachment/album/201910/07/115207h9eshwh1sil1wsho.png "Minecraft Gameover")

文章到这里就结束了，朋友们！如果你想了解更多，具体可以查看我的 [GitHub 存储库](https://github.com/abhiTamrakar/playground/tree/master/bash_games)，那儿有这个扫雷游戏的源代码，并且你还能找到更多用 Bash 编写的游戏。 我希望，这篇文章能激起你学习 Bash 的兴趣，并乐在其中。

---

via: <https://opensource.com/article/19/9/advanced-bash-building-minesweeper>

作者：[Abhishek Tamrakar](https://opensource.com/users/tamrakar) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wenwensnow](https://github.com/wenwensnow) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


4 种开源云安全工具

Summary: 查找并排除你存储在 AWS 和 GitHub 中的数据里的漏洞。

查找并排除你存储在 AWS 和 GitHub 中的数据里的漏洞。

>
> 查找并排除你存储在 AWS 和 GitHub 中的数据里的漏洞。
>
>
>

![](/data/attachment/album/201910/07/140417vhywycwwdoakzyqi.jpg)

如果你的日常工作是开发者、系统管理员、全栈工程师或者是网站可靠性工程师（SRE），工作内容包括使用 Git 从 GitHub 上推送、提交和拉取，并部署到亚马逊 Web 服务上（AWS），安全性就是一个需要持续考虑的一个点。幸运的是，开源工具能帮助你的团队避免犯常见错误，这些常见错误会导致你的组织损失数千美元。

本文介绍了四种开源工具，当你在 GitHub 和 AWS 上进行开发时，这些工具能帮助你提升项目的安全性。同样的，本着开源的精神，我会与三位安全专家——[Travis McPeak](https://twitter.com/travismcpeak?lang=en)，奈飞高级云安全工程师；[Rich Monk](https://github.com/rmonk)，红帽首席高级信息安全分析师；以及 [Alison Naylor](https://www.linkedin.com/in/alperkins/)，红帽首席信息安全分析师——共同为本文做出贡献。

我们已经按场景对每个工具都做了区分，但是它们并不是相互排斥的。

### 1、使用 gitrob 发现敏感数据

你需要发现任何出现于你们团队的 Git 仓库中的敏感信息，以便你能将其删除。借助专注于攻击应用程序或者操作系统的工具以使用红/蓝队模型，这样可能会更有意义，在这个模型中，一个信息安全团队会划分为两块，一个是攻击团队（又名红队），以及一个防守团队（又名蓝队）。有一个红队来尝试渗透你的系统和应用要远远好于等待一个攻击者来实际攻击你。你的红队可能会尝试使用 [Gitrob](https://github.com/michenriksen/gitrob)，该工具可以克隆和爬取你的 Git 仓库，以此来寻找凭证和敏感信息。

即使像 Gitrob 这样的工具可以被用来造成破坏，但这里的目的是让你的信息安全团队使用它来发现无意间泄露的属于你的组织的敏感信息（比如 AWS 的密钥对或者是其他被失误提交上去的凭证）。这样，你可以修整你的仓库并清除敏感数据——希望能赶在攻击者发现它们之前。记住不光要修改受影响的文件，还要[删除它们的历史记录](https://help.github.com/en/articles/removing-sensitive-data-from-a-repository)。

### 2、使用 git-secrets 来避免合并敏感数据

虽然在你的 Git 仓库里发现并移除敏感信息很重要，但在一开始就避免合并这些敏感信息岂不是更好？即使错误地提交了敏感信息，使用 [git-secrets](https://github.com/awslabs/git-secrets) 可以避免你陷入公开的困境。这款工具可以帮助你设置钩子，以此来扫描你的提交、提交信息和合并信息，寻找常见的敏感信息模式。注意你选择的模式要匹配你的团队使用的凭证，比如 AWS 访问密钥和秘密密钥。如果发现了一个匹配项，你的提交就会被拒绝，一个潜在的危机就此得到避免。

为你已有的仓库设置 git-secrets 是很简单的，而且你可以使用一个全局设置来保护所有你以后要创建或克隆的仓库。你同样可以在公开你的仓库之前，使用 git-secrets 来扫描它们（包括之前所有的历史版本）。

### 3、使用 Key Conjurer 创建临时凭证

有一点额外的保险来防止无意间公开了存储的敏感信息，这是很好的事，但我们还可以做得更好，就完全不存储任何凭证。追踪凭证，谁访问了它，存储到了哪里，上次更新是什么时候——太麻烦了。然而，以编程的方式生成的临时凭证就可以避免大量的此类问题，从而巧妙地避开了在 Git 仓库里存储敏感信息这一问题。使用 [Key Conjurer](https://github.com/RiotGames/key-conjurer)，它就是为解决这一需求而被创建出来的。有关更多 Riot Games 为什么创建 Key Conjurer，以及 Riot Games 如何开发的 Key Conjurer，请阅读 [Key Conjurer：我们最低权限的策略](https://technology.riotgames.com/news/key-conjurer-our-policy-least-privilege)。

### 4、使用 Repokid 自动化地提供最小权限

任何一个参加过基本安全课程的人都知道，设置最小权限是基于角色的访问控制的最佳实现。难过的是，离开校门，会发现手动运用最低权限策略会变得如此艰难。一个应用的访问需求会随着时间的流逝而变化，开发人员又太忙了没时间去手动削减他们的权限。[Repokid](https://github.com/Netflix/repokid) 使用 AWS 提供提供的有关身份和访问管理（IAM）的数据来自动化地调整访问策略。Repokid 甚至可以在 AWS 中为超大型组织提供自动化地最小权限设置。

### 工具而已，又不是大招

这些工具并不是什么灵丹妙药，它们只是工具！所以，在尝试使用这些工具或其他的控件之前，请和你的组织里一起工作的其他人确保你们已经理解了你的云服务的使用情况和用法模式。

应该严肃对待你的云服务和代码仓库服务，并熟悉最佳实现的做法。下面的文章将帮助你做到这一点。

**对于 AWS：**

* [管理 AWS 访问密钥的最佳实现](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html)
* [AWS 安全审计指南](https://docs.aws.amazon.com/general/latest/gr/aws-security-audit-guide.html)

**对于 GitHub：**

* [介绍一种新方法来让你的代码保持安全](https://github.blog/2019-05-23-introducing-new-ways-to-keep-your-code-secure/)
* [GitHub 企业版最佳安全实现](https://github.blog/2015-10-09-github-enterprise-security-best-practices/)

同样重要的一点是，和你的安全团队保持联系；他们应该可以为你团队的成功提供想法、建议和指南。永远记住：安全是每个人的责任，而不仅仅是他们的。

---

via: <https://opensource.com/article/19/9/open-source-cloud-security>

作者：[Alison Naylor](https://opensource.com/users/asnaylor),[Anderson Silva](https://opensource.com/users/ansilva) 选题：[lujun9972](https://github.com/lujun9972) 译者：[hopefully2333](https://github.com/hopefully2333) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


现在你可以借助 Insync 在 Linux 中原生使用 OneDrive

Summary: 当 Insync 在 Linux 上支持 Google Drive 时，它变成了 Linux 上非常流行的高级第三方同步工具。我们有篇对 Insync 支持 Google Drive 的详细点评文章。而最近发布的 Insync 3 支持了 OneDrive。

国内我还是选择坚果云

ubuntu 也可以吗？

ubuntu 也可以吗？

[OneDrive](https://onedrive.live.com) 是微软的一项云存储服务，它为每个用户提供 5GB 的免费存储空间。它已与微软帐户集成，如果你使用 Windows，那么已在其中预安装了 OneDrive。

OneDrive 无法在 Linux 中作为桌面应用使用。你可以通过网页访问已存储的文件，但无法像在文件管理器中那样使用云存储。

好消息是，你现在可以使用一个非官方工具，它可让你在 Ubuntu 或其他 Linux 发行版中使用 OneDrive。

当 [Insync](https://www.insynchq.com) 在 Linux 上支持 Google Drive 时，它变成了 Linux 上非常流行的高级第三方同步工具。我们有篇对 [Insync 支持 Google Drive](https://itsfoss.com/insync-linux-review/) 的详细点评文章。

而最近[发布的 Insync 3](https://www.insynchq.com/blog/insync-3/) 支持了 OneDrive。因此在本文中，我们将看下如何在 Insync 中使用 OneDrive 以及它的新功能。

>
> 非 FOSS 警告
>
>
> 少数开发者会对非 FOSS 软件引入 Linux 感到痛苦。作为专注于桌面 Linux 的门户，即使不是 FOSS，我们也会在此介绍此类软件。
>
>
> Insync 3 既不是开源软件，也不免费使用。你只有 15 天的试用期进行测试。如果你喜欢它，那么可以按每个帐户终生 29.99 美元的费用购买。
>
>
> 我们不会拿钱来推广它们（以防你这么想）。我们不会在这里这么做。
>
>
>

### 在 Linux 中通过 Insync 获得原生 OneDrive 体验

![](/data/attachment/album/201910/08/115426ho4nonbbn8nbxgbn.png)

尽管它是一个付费工具，但依赖 OneDrive 的用户或许希望在他们的 Linux 系统中获得同步 OneDrive 的无缝体验。

首先，你需要从[官方页面](https://www.insynchq.com/downloads?start=true)下载适合你 Linux 发行版的软件包。

* [下载 Insync](https://www.insynchq.com/downloads)

你也可以选择添加仓库并进行安装。你将在 Insync 的[官方网站](https://www.insynchq.com/downloads)看到说明。

安装完成后，只需启动并选择 OneDrive 选项。

![](/data/attachment/album/201910/08/115431y5i8lecf0c8w5fe6.png)

另外，要注意的是，你添加的每个 OneDrive 或 Google Drive 帐户都需要单独的许可证。

现在，在授权 OneDrive 帐户后，你必须选择一个用于同步所有内容的基础文件夹，这是 Insync 3 中的一项新功能。

![Insync 3 Base Folder](/data/attachment/album/201910/08/115431mpnsnd1dpnx2r2rn.png)

除此之外，设置完成后，你还可以选择性地同步本地或云端的文件/文件夹。

![Insync Selective Sync](/data/attachment/album/201910/08/115436vztr1oi9iciokwpl.png)

你还可以通过添加自己的规则来自定义同步选项，以忽略/同步所需的文件夹和文件，这完全是可选的。

![Insync Customize Sync Preferences](/data/attachment/album/201910/08/115436es2fwjaq3jzx8ljd.png)

最后，就这样完成了。

![Insync 3](/data/attachment/album/201910/08/115437wgsswxllgwwigwle.png)

你现在可以在包括带有 Insync 的 Linux 桌面在内的多个平台使用 OneDrive 开始同步文件/文件夹。除了上面所有新功能/更改之外，你还可以在 Insync 上获得更快/更流畅的体验。

此外，借助 Insync 3，你可以查看同步进度：

![](/data/attachment/album/201910/08/115437u7fvbtsw3t3fbt03.png)

### 总结

总的来说，对于希望在 Linux 系统上同步 OneDrive 的用户而言，Insync 3 是令人印象深刻的升级。如果你不想付款，你可以尝试其他 [Linux 的免费云服务](https://itsfoss.com/cloud-services-linux/)。

你如何看待 Insync？如果你已经在使用它，到目前为止的体验如何？在下面的评论中让我们知道你的想法。

---

via: <https://itsfoss.com/use-onedrive-on-linux/>

作者：[Ankush Das](https://itsfoss.com/author/ankush/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用 guiscrcpy 将你的安卓手机的屏幕投射到你的电脑

Summary: 使用这个基于 scrcpy 的开源应用从你的电脑上访问你的安卓设备。

使用这个基于 scrcpy 的开源应用从你的电脑上访问你的安卓设备。

>
> 使用这个基于 scrcpy 的开源应用从你的电脑上访问你的安卓设备。
>
>
>

![](/data/attachment/album/201910/08/123143nlz718152v5nf5n8.png)

在未来，你所需的一切信息皆触手可及，并且全部会以全息的形式出现在空中，即使你在驾驶汽车时也可以与之交互。不过，那是未来，在那一刻到来之前，我们所有人都只能将信息分散在笔记本电脑、手机、平板电脑和智能冰箱上。不幸的是，这意味着当我们需要来自该设备的信息时，我们通常必须查看该设备。

虽然不完全是像全息终端或飞行汽车那样酷炫，但 [srevin saju](http://opensource.com/users/srevinsaju) 开发的 [guiscrcpy](https://github.com/srevinsaju/guiscrcpy) 是一个可以在一个地方整合多个屏幕，让你有一点未来感觉的应用程序。

Guiscrcpy 是一个基于屡获殊荣的一个开源引擎 [scrcpy](https://github.com/Genymobile/scrcpy) 的一个开源项目（GUN GPLv3 许可证）。使用 Guiscrcpy 可以将你的安卓手机的屏幕投射到你的电脑，这样你就可以查看手机上的一切东西。Guiscrcpy 支持 Linux、Windows 和 MacOS。

不像其他 scrcpy 的替代软件一样，Guiscrcpy 并不仅仅是 scrcpy 的一个简单的复制品。该项目优先考虑了与其他开源项目的协作。因此，Guiscrcpy 对 scrcpy 来说是一个扩展，或者说是一个用户界面层。将 Python 3 GUI 与 scrcpy 分开可以确保没有任何东西干扰 scrcpy 后端的效率。你可以投射到 1080P 分辨率的屏幕，因为它的超快的渲染速度和超低的 CPU 使用，即使在低端的电脑上也可以运行的很顺畅。

Scrcpy 是 Guiscrcpy 项目的基石。它是一个基于命令行的应用，因此它没有处理你的手势操作的用户界面。它也没有提供返回按钮和主页按钮，而且它需要你对 [Linux 终端](https://www.redhat.com/sysadmin/navigating-filesystem-linux-terminal)比较熟悉。Guiscrcpy 给 scrcpy 添加了图形面板。因此，任何用户都可以使用它，而且不需要通过网络发送任何信息就可以投射和控制他的设备。Guiscrcpy 同时也为 Windows 用户和 Linux 用户提供了编译好的二进制文件，以方便你的使用。

### 安装 Guiscrcpy

在你安装 Guiscrcpy 之前，你需要先安装它的依赖包。尤其是要安装 scrcpy。安装 scrcpy 最简单的方式可能就是使用对于大部分 Linux 发行版都安装了的 [snap](https://snapcraft.io/) 工具。如果你的电脑上安装并使用了 snap，那么你就可以使用下面的命令来一步安装 scrcpy。

```
$ sudo snap install scrcpy
```

当你安装完 scrcpy，你就可以安装其他的依赖包了。[Simple DirectMedia Layer](https://www.libsdl.org/)（SDL 2.0） 是一个显示和控制你设备屏幕的工具包。[Android Debug Bridge](https://developer.android.com/studio/command-line/adb) (ADB) 命令可以连接你的安卓手机到电脑。

在 Fedora 或者 CentOS：

```
$ sudo dnf install SDL2 android-tools
```

在 Ubuntu 或者 Debian：

```
$ sudo apt install SDL2 android-tools-adb
```

在另一个终端中，安装 Python 依赖项：

```
$ python3 -m pip install -r requirements.txt --user
```

### 设置你的手机

为了能够让你的手机接受 adb 连接。必须让你的手机开启开发者选项。为了打开开发者选项，打开“设置”，然后选择“关于手机”，找到“版本号”（它也可能位于“软件信息”面板中）。不敢置信，只要你连续点击“版本号”七次，你就可以打开开发者选项。（LCTT 译注：显然这里是以 Google 原生的 Android 作为说明的，你的不同品牌的安卓手机打开开发者选项的方式或有不同。）

![Enabling Developer Mode](/data/attachment/album/201910/08/123228p6so9wwzwi703ow7.jpg "Enabling Developer Mode")

更多更全面的连接手机的方式，请参考[安卓开发者文档](https://developer.android.com/studio/debug/dev-options)。

一旦你设置好了你的手机，将你的手机通过 USB 线插入到你的电脑中（或者通过无线的方式进行连接，确保你已经配置好了无线连接）。

### 使用 Guiscrcpy

当你启动 guiscrcpy 的时候，你就能看到一个主控制窗口。点击窗口里的 “Start scrcpy” 按钮。只要你设置好了开发者模式并且通过 USB 或者 WiFi 将你的手机连接到电脑。guiscrcpy 就会连接你的手机。

![Guiscrcpy main screen](/data/attachment/album/201910/08/123231nljld9jnkyj3dny3.png "Guiscrcpy main screen")

它还包括一个可写入的配置系统，你可以将你的配置文件写入到 `~/.config` 目录。可以在使用前保存你的首选项。

guiscrcpy 底部的面板是一个浮动的窗口，可以帮助你执行一些基本的控制动作。它包括了主页按钮、返回按钮、电源按钮以及一些其他的按键。这些按键在安卓手机上都非常常用。值得注意的是，这个模块并不是与 scrcpy 的 SDL 进行交互。因此，它可以毫无延迟的执行。换句话说，这个操作窗口是直接通过 adb 与你的手机进行交互而不是通过 scrcpy。

![guiscrcpy's bottom panel](/data/attachment/album/201910/08/123232gk25dzbcg32in3k2.png "guiscrcpy's bottom panel")

这个项目目前十分活跃，不断地有新的特性加入其中。最新版本的具有了手势操作和通知界面。

有了这个 guiscrcpy，你不仅仅可以在你的电脑屏幕上看到你的手机，你还可以就像操作你的实体手机一样点击 SDL 窗口，或者使用浮动窗口上的按钮与之进行交互。

![guiscrcpy running on Fedora 30](/data/attachment/album/201910/08/123236ccvjc41z1pw4vjds.jpg "guiscrcpy running on Fedora 30")

Guiscrcpy 是一个有趣且实用的应用程序，它提供的功能应该是任何现代设备（尤其是 Android 之类的平台）的正式功能。自己尝试一下，为当今的数字生活增添一些未来主义的感觉。

---

via: <https://opensource.com/article/19/9/mirror-android-screen-guiscrcpy>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[amwps290](https://github.com/amwps290) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


我买了一台 Linux 笔记本

IBM T410，改光驱为硬盘托架启动，使用FEDORA。

来自江苏南京的 Microsoft Edge 18.18362|Windows 10 用户

IBM T410，改光驱为硬盘托架启动，使用FEDORA。

邮寄，海关，售后这块是怎么解决的？

>
> Tuxedo 让买一台开箱即用的 Linux 笔记本变得容易。
>
>
>

![](/data/attachment/album/201910/08/133924vnmbklqh5jkshkmj.jpg)

最近，我开始使用我买的 Linux 笔记本计算机 Tuxedo Book BC1507。十年前，如果有人告诉我，十年后我可以从 [System76](https://system76.com/)、[Slimbook](https://slimbook.es/en/) 和 [Tuxedo](https://www.tuxedocomputers.com/) 等公司购买到高质量的“企鹅就绪”的笔记本电脑。我可能会发笑。好吧，现在我也在笑，但是很开心！

除了为免费/自由开源软件（FLOSS）设计计算机之外，这三家公司最近[宣布](https://www.tuxedocomputers.com/en/Infos/News/Tuxedo-Computers-stands-for-Free-Software-and-Security-.tuxedo)都试图通过切换到[Coreboot](https://coreboot.org/)来消除专有的 BIOS 软件。

### 买一台

Tuxedo Computers 是一家德国公司，生产支持 Linux 的笔记本电脑。实际上，如果你要使用其他的操作系统，则它的价格会更高。

购买他们的计算机非常容易。Tuxedo 提供了许多付款方式：不仅包括信用卡，而且还包括 PayPal 甚至银行转帐（LCTT 译注：我们需要支付宝和微信支付……此外，要国际配送，还需要支付运输费和清关费用等）。只需在 Tuxedo 的网页上填写银行转帐表格，公司就会给你发送银行信息。

Tuxedo 可以按需构建每台计算机，只需选择基本模型并浏览下拉菜单以选择不同的组件，即可轻松准确地选择所需内容。页面上有很多信息可以指导你进行购买。

如果你选择的 Linux 发行版与推荐的发行版不同，则 Tuxedo 会进行“网络安装”，因此请准备好网络电缆以完成安装，也可以将你首选的镜像文件刻录到 USB 盘上。我通过外部 DVD 阅读器来安装刻录了 openSUSE Leap 15.1 安装程序的 DVD，但是你可用你自己的方式。

我选择的型号最多可以容纳两个磁盘：一个 SSD，另一个可以是 SSD 或常规硬盘。由于已经超出了我的预算，因此我决定选择传统的 1TB 磁盘并将 RAM 增加到 16GB。该处理器是具有四个内核的第八代 i5。我选择了背光西班牙语键盘、1920×1080/96dpi 屏幕和 SD 卡读卡器。总而言之，这是一个很棒的系统。

如果你对默认的英语或德语键盘感觉满意，甚至可以要求在 Meta 键上印上一个企鹅图标！我需要的西班牙语键盘则不提供此选项。

### 收货并开箱使用

付款完成后仅六个工作日，完好包装的计算机就十分安全地到达了我家。打开计算机包装并解锁电池后，我准备好开始浪了。

![Tuxedo Book BC1507](/data/attachment/album/201910/08/134049x7m8vlvfqmxl8x38.jpg "Tuxedo Book BC1507")

*我的（物理）桌面上的新玩具。*

该电脑的设计确实很棒，而且感觉扎实。即使此型号的外壳不是铝制的（LCTT 译注：他们有更好看的铝制外壳的型号），也可以保持凉爽。风扇真的很安静，气流像许多其他笔记本电脑一样导向后边缘，而不是流向侧面。电池可提供数小时的续航时间。BIOS 中的一个名为 FlexiCharger 的选项会在达到一定百分比后停止为电池充电，因此在插入电源长时间工作时，无需卸下电池。

键盘真的很舒适，而且非常安静。甚至触摸板按键也很安静！另外，你可以轻松调整背光键盘上的光强度。

最后，很容易访问笔记本电脑中的每个组件，因此可以毫无问题地对计算机进行更新或维修。Tuxedo 甚至送了几个备用螺丝！

### 结语

经过一个月的频繁使用，我对该系统感到非常满意。它完全满足了我的要求，并且一切都很完美。

因为它们通常是高端系统，所以包含 Linux 的计算机往往比较昂贵。如果你将 Tuxedo 或 Slimbook 电脑的价格与更知名品牌的类似规格的价格进行比较，价格相差无几。如果你想要一台使用自由软件的强大系统，请毫不犹豫地支持这些公司：他们所提供的物有所值。

请在评论中让我们知道你在 Tuxedo 和其他“企鹅友好”公司的经历。

---

本文基于 Ricardo 的博客 [From Mind to Type](https://frommindtotype.wordpress.com/) 上发表的“ [我的新企鹅笔记本电脑：Tuxedo-Book-BC1507](https://frommindtotype.wordpress.com/2019/06/17/my-new-penguin-ready-laptop-tuxedo-book-bc1507/)”。

---

via: <https://opensource.com/article/19/7/linux-laptop>

作者：[Ricardo Berlasso](https://opensource.com/users/rgb-es) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


大势已来：阿里云梭哈云原生

Summary: 阿里云正在云原生的路上狂奔，将各个产品、服务都押宝在元原生的领域上。

阿里云正在云原生的路上狂奔，将各个产品、服务都押宝在元原生的领域上。

![](/data/attachment/album/201910/09/081514u0qs7mz0kjk5gtmk.jpg)

### 云原生是什么？

技术圈总是在不停地蹦各种新名词。也不知道从什么时候开始，人们慢慢不怎么提“云计算”这个名词了，而是频繁提到一个新名词“云原生”，好像不这么提就不足以体现云计算原住民的身份。不过，要真的问什么是“云原生”，其实很多人都说不太清楚。随着云原生生态如火如荼的发展，甚至连 CNCF 官方都觉得有必要专门做个定义出来：

![](/data/attachment/album/201910/09/081456oh5m82y8wozzgin7.png)

前一段时间，我在云栖大会上见到了阿里云的李响，就有人问他，“怎么理解‘云原生’？”作为 CNCF 的技术监督委员会成员的李响，以他的角度对此作了阐释：

“我觉得云原生本身实际上就是比较泛的概念，它最终的目标就是利用云上的资源、云上的服务来重构软件开发以及运行时的生命周期。简而言之就是怎么更好利用云。……随着云的发展，云原生本身也会有一些变化，大家接受云原生的理念和实现云原生的情况也会有变化。……我觉得不用太把云原生本身在一个框框里圈定，它更多还是一个核心的概念——更好地利用云释放云的红利，产生相关的技术让大家去实践。”

在我看来，虽然现在云原生的概念的内涵和外延都在不断的变化当中，但是不可否认的是，云计算生态已经从最初的巨石应用、刚性的分布式计算逐渐演变到原生地基于云计算环境进行设计、开发、部署、运维和弹性伸缩。可以说，云原生重新定义了云计算。

借助于云原生技术，一个计算系统可以很便捷的从一个环境中迁移至另外一个环境当中，而这在之前几年，几乎还是不可想象的。就这个场景，阿里云举了一个例子：比如像三维家，他们在上海云栖大会上宣布了全站上云的消息，因为他们已经应用了云原生的方式，仅花了三天把全部业务迁到阿里云上。而在迁移之后，三维家现在可以利用云原生的方式可以充分发挥云计算的弹性，三分钟之内就可以创建 100 个神龙节点去应对突发的业务需求，极大提升企业 IT 的灵活性，并且降低了 IT 成本。三维家表示，“阿里云的容器生态系统打造得非常完善，从监控、日志、服务暴露、应用拓扑、伸缩扩容方面能够做的更加灵活；基础设施的建设和维护稳定性交给阿里云，目前没有出现过问题。”

### 云原生进化

今年我参加云栖大会，有一个明显的感受就是，阿里云在不断的大声谈论云原生。事实上阿里云早已是云原生计算基金会的成员（现在是白金成员），也在这个领域耕耘良久，但是今年，无论是多到你参加不过来的各种主题演讲，还是各种产品和服务的消息，都在不断的讲，云原生、云原生……

在过去大家更多是把互联网和移动互联网的应用，大部分是无状态应用部署在容器平台之上，今年越来越多的企业开始把有状态的应用、交易类的应用以原生化的方式进行交付，进行自动化的运维。

![](/data/attachment/album/201910/09/081823llbfsaxi95sxl45a.jpg)

这次云栖大会上阿里云还发布了 ACK 2.0。ACK 是阿里云容器服务 Kubernetes 版，它提供了高性能可伸缩的容器应用管理能力，支持企业级 Kubernetes 容器化应用的全生命周期管理，简化了集群的搭建和扩容等工作，整合了阿里云虚拟化、存储、网络和安全能力，以打造云端最佳的 Kubernetes 容器化应用运行环境。

关于阿里云容器服务，阿里云的易立说，从 2015 年底公测、2016 年中正式上线到现在的 4 年时间发展非常快，现在已经覆盖了阿里云全球 20 个地域，支撑了国内外数千家客户的生态系统。同时容器产品在持续保持增长，过去 3 年都能保持 400% 以上的增长速度，现在一个月下载次数超过 3 亿次。今年在 Forrester 全球公共云容器平台的评测里面，阿里云是国内排名第一，在 Gartner 报告也唯一入选公共云容器平台竞争格局。

阿里云容器服务优化整合了阿里云整体的计算、存储、网络、安全等核心能力。

比如说计算，不但能够支持强大虚拟机，像神龙这样的裸金属服务，还有异构计算的 CPU、GPU，未来也会包括云栖大会当天发布的含光芯片，通过容器的高效调度能够让 GPU 的利用率提升了 5 倍，而且容器产品能充分把计算资源弹性发挥出来，可以实现分钟级千节点的弹性伸缩，这对客户来说是非常重要的。

而在容器网络方面，它和阿里云的虚拟化网络进行了优化集成，可以实现原生网络一样的性能，与社区的 VXLAN 实现相比提升了 20% 性能。

在存储方面支持阿里云所有的存储产品，包括块存储、网络存储、对象存储等。针对容器场景进行了很多创新，比如说容器高密度部署时容器之间会对 I/O 进行争抢，通过跟操作系统团队进行深入合作，实现了更好的存储 I/O 隔离。另外，还实现了透明、高效的存储缓存，可以低成本支持像高性能计算和AI场景下大数据吞吐量的需求。

本次云栖大会上阿里云发布的 ACK 2.0 面向云原生进化，最重要的是它为整个企业上云奠定了一个新的基石。首先是容器服务全球化的部署，利用在阿里巴巴集团的大规模生产实践沉淀，建立了这样的基础设施。其次，云边端一体化可以实现边缘节点极大降低访问的延迟降低 75%。第三，可以让客户把他的私有云和云端利用 Kubernetes 进行统一管理，应用发布效率可以提升三倍，另外，还提供了全链路的安全架构，对安全风险进行监控。

对于云原生的发展，作为阿里云内部基础设施负责人的李响，在帮助阿里经济体以更为云原生的方式上云，在推动阿里经济体采用 Kubernetes、Service Mesh、Serverless 这些技术。他谈到：

>
> “阿里和蚂蚁有着最大的 Kubernetes 集群，我们对 Kubernetes 上游拓展性、功能性是最大的贡献者之一，我们今年尝试落地Service Mesh，之前大家对 Service Mesh 的疑问是，它能不能应对一个复杂的场景，尤其和传统的微服务体系对接的场景。在阿里巴巴内部要验证这件事情，我们要告诉大家可以做到，而且我们要告诉大家怎么做到，后续会提供解决方案让大家去做这件事情。
>
>
> 第二，大家会思考 Service Mesh 的规模性是不是足够，阿里巴巴其实有巨大规模性的挑战，我们也会解决 Service Mesh 规模性的问题。我们认为阿里巴巴能够使用 Service Mesh，我想世界上 99% 的公司都可以使用 Service Mesh， 而不会遇到它的规模性问题。
>
>
> 第三，Service Mesh 是不是会影响核心链路上的性能问题，会不会影响在核心时刻的性能。我们也会在双 11 这种洪峰流量，对流量要求极高的情况下去验证 Service Mesh，使用 Service Mesh，去打磨 Service Mesh，所有打磨的东西会反馈到上流，让用户、开发者享受到这种红利。
>
>
> 第四，阿里巴巴通过这些事情培养出一批靠谱的工程师，我们有非常强的兜底能力，当用户遇到任何问题，阿里巴巴都能帮你解决问题，阿里巴巴真的是运营这套体系的，有这个生产实践的经验。
>
>
> 阿里巴巴真正把‘云原生’新的概念，在我们认为正确的方向进行落地、进行打磨，最后交付给客户。所有这些东西，当我们说阿里巴巴云上有这样的产品，一定是可靠的，一定是稳定的。”
>
>
>

### 容器安全是重点

当然我们也看到企业客户在使用云原生技术过程中面对几个挑战，第一个挑战就是安全。

安全是企业上云的首要关注。云原生加剧了这个挑战，云原生平台高密度、高动态部署使得遭受攻击可能性增加，而且一旦遭受攻击，用户不知道是谁受到攻击，也没有办法实时应对。

安全是体系性的东西，永远在最弱的一环去攻破整个企业的安全体系。阿里云容器服务实现了非常全面的端到端的云原生安全的架构，包括基础设施的安全，跟阿里云的云安全基础设施紧密基础，利用 RAM 进行认证、鉴权和审计，支持存储的 BYOK 加密等，提供了一个安全的云基础设施。

同时，在应用的生命周期里面用了安全的镜像检测，上线之前要进行扫描，上线之后会进行实时的安全检测。还有运行时的安全，因为安全的风险无处不在，一旦出现了安全问题必须第一时间对它进行监控、报警。

对于企业来讲，大量采用容器之后面临的挑战之一就是安全隔离。比如说一台机器上要混布多种类型的应用，但是有些像金融交易的应用，安全级别敏感性会很高，不希望受到其他应用的攻击和干扰。另外企业除了自己的应用还要部署第三方应用，这个过程中对一些不可信的应用要进行安全的隔离，阿里云引入了安全沙箱一系列的技术。传统的容器 RunC 用是共享内核的机制，很高效，但是安全隔离做得不好，现在可以利用安全沙箱可以进行安全隔离。

在这方面阿里云有一些差异化的优势：首先就是对它进行大量的性能优化，比如说它的网络跟原生的进程没有任何区别，网络性能非常好。整体能够达到 90% 的原生性能，对用户来讲可以获得非常好的安全性，同时对性能损耗是可以接受的。另外，能够让用户自主选择是 RunC 还是安全沙箱，两种容器运行时用户体验是完全一致的，用户可以根据自己对业务需求来选择合适的容器应用技术。

![](/data/attachment/album/201910/09/081854yoszbbkymis7ke7z.jpg)

在安全容器领域有几个重要的项目，如 Google 的 gVisor，以及已经属于蚂蚁金服旗下的 Kata 容器项目等，不过和易立的沟通当中，我了解到阿里云容器服务的安全容器所采用的技术并非照搬 Kata 容器技术，而是集成了目前主流的安全容器项目，加以自身的创新而成的。阿里经济体实际上在容器安全方面投入非常大，包括 Kata，还有其他几种技术。他们与蚂蚁金服、阿里的操作系统团队合作一起来提供这样商业化安全容器的实现。这次发布的安全沙箱容器底层技术针对阿里云进行了大量优化，跟 Kata 技术有些类似，但是里面有很多部分不同，性能也做了大量的优化。

现在提供的是基于虚拟化隔离的安全技术，后续会陆续提供其他的技术能力，它们的隔离级别和适用场景是不同的，用户只要去选择就好了，在保证用户体验是一致的基础上，对用户是透明的。

### 结语

我们看到，阿里云正在云原生的路上狂奔，将各个产品、服务都押宝在元原生的领域上。最后，让我们用李响的一段话来结束这篇文章：“新兴的应用，或者是新兴的领域，我们建议你使用容器轻量级自动化平台，现在我们阿里云、ACK 都是朝着这种模式跟大家宣导的。我们要去帮助开发者，引导开发者从非原生的体系向云原生体系去转移，我觉得这条道路非常重要，这也是阿里云的责任，带动整个国内的基础设施，带动国内云原生体系发展，我们要去承担这件事情。”


CentOS 8 安装图解

Summary: 在这篇文章中，我们会使用图解的方式演示 CentOS 8 的安装方法。

新手入门

很详细！！！<br />
很贴心

很详细！！！<br />
很贴心

很详细！！！<br />
很贴心

很详细！！！<br />
很贴心

安装完成之后重启开机有三个选项是怎么回事呢？

有咩有针对“带GUI图形界面的安装”子菜单中，各个选项的讲解和安装推荐 ？？

写的很详细，优秀的

在这篇文章中，我们会使用图解的方式演示 CentOS 8 的安装方法。

![](/data/attachment/album/201910/09/121153tj05o5t2ee79jl63.png)

继 RHEL 8 发布之后，CentOS 社区也发布了让人期待已久的 CentOS 8，并发布了两种模式：

* CentOS stream：滚动发布的 Linux 发行版，适用于需要频繁更新的开发者
* CentOS：类似 RHEL 8 的稳定操作系统，系统管理员可以用其部署或配置服务和应用

在这篇文章中，我们会使用图解的方式演示 CentOS 8 的安装方法。

### CentOS 8 的新特性

* DNF 成为了默认的软件包管理器，同时 yum 仍然是可用的
* 使用网络管理器（`nmcli` 和 `nmtui`）进行网络配置，移除了网络脚本
* 使用 Podman 进行容器管理
* 引入了两个新的包仓库：BaseOS 和 AppStream
* 使用 Cockpit 作为默认的系统管理工具
* 默认使用 Wayland 作为显示服务器
* `iptables` 将被 `nftables` 取代
* 使用 Linux 内核 4.18
* 提供 PHP 7.2、Python 3.6、Ansible 2.8、VIM 8.0 和 Squid 4

### CentOS 8 所需的最低硬件配置:

* 2 GB RAM
* 64 位 x86 架构、2 GHz 或以上的 CPU
* 20 GB 硬盘空间

### CentOS 8 安装图解

#### 第一步：下载 CentOS 8 ISO 文件

在 CentOS 官方网站 <https://www.centos.org/download/> 下载 CentOS 8 ISO 文件。

#### 第二步： 创建 CentOS 8 启动介质（USB 或 DVD）

下载 CentOS 8 ISO 文件之后，将 ISO 文件烧录到 USB 移动硬盘或 DVD 光盘中，作为启动介质。

然后重启系统，在 BIOS 中设置为从上面烧录好的启动介质启动。

#### 第三步：选择“安装 CentOS Linux 8.0”选项

当系统从 CentOS 8 ISO 启动介质启动之后，就可以看到以下这个界面。选择“Install CentOS Linux 8.0”（安装 CentOS Linux 8.0）选项并按回车。

![Choose-Install-CentOS8](/data/attachment/album/201910/09/121203kwt4yvjxmnvzrjrp.jpg)

#### 第四步：选择偏好语言

选择想要在 CentOS 8 **安装过程**中使用的语言，然后继续。

![Select-Language-CentOS8-Installation](/data/attachment/album/201910/09/121203dhfnlfyh8p0ajbqz.jpg)

#### 第五步：准备安装 CentOS 8

这一步我们会配置以下内容：

* 键盘布局
* 日期和时间
* 安装来源
* 软件选择
* 安装目标
* Kdump

![Installation-Summary-CentOS8](/data/attachment/album/201910/09/121204djyz9iwhf7re9nrn.jpg)

如上图所示，安装向导已经自动提供了“<ruby> 键盘布局 <rt>  Keyboard </rt></ruby>”、“<ruby> 时间和日期 <rt>  Time & Date </rt></ruby>”、“<ruby> 安装来源 <rt>  Installation Source </rt></ruby>”和“<ruby> 软件选择 <rt>  Software Selection </rt></ruby>”的选项。

如果你需要修改以上设置，点击对应的图标就可以了。例如修改系统的时间和日期，只需要点击“<ruby> 时间和日期 <rt>  Time & Date </rt></ruby>”，选择正确的时区，然后点击“<ruby> 完成 <rt>  Done </rt></ruby>”即可。

![TimeZone-CentOS8-Installation](/data/attachment/album/201910/09/121204ed2al52p527zbzbp.jpg)

在软件选择选项中选择安装的模式。例如“<ruby> 包含图形界面 <rt>  Server with GUI </rt></ruby>”选项会在安装后的系统中提供图形界面，而如果想安装尽可能少的额外软件，可以选择“<ruby> 最小化安装 <rt>  Minimal Install </rt></ruby>”。

![Software-Selection-CentOS8-Installation](/data/attachment/album/201910/09/121205adk7zvsxxfh1av25.jpg)

这里我们选择“<ruby> 包含图形界面 <rt>  Server with GUI </rt></ruby>”，点击“<ruby> 完成 <rt>  Done </rt></ruby>”。

Kdump 功能默认是开启的。尽管这是一个强烈建议开启的功能，但也可以点击对应的图标将其关闭。

如果想要在安装过程中对网络进行配置，可以点击“<ruby> 网络与主机名 <rt>  Network & Host Name </rt></ruby>”选项。

![Networking-During-CentOS8-Installation](/data/attachment/album/201910/09/121205com66etz1eql6v2q.jpg)

如果系统连接到启用了 DHCP 功能的调制解调器上，就会在启动网络接口的时候自动获取一个 IP 地址。如果需要配置静态 IP，点击“<ruby> 配置 <rt>  Configure </rt></ruby>”并指定 IP 的相关信息。除此以外我们还将主机名设置为 “linuxtechi.com”。

完成网络配置后，点击“<ruby> 完成 <rt>  Done </rt></ruby>”。

最后我们要配置“<ruby> 安装目标 <rt>  Installation Destination </rt></ruby>”，指定 CentOS 8 将要安装到哪一个硬盘，以及相关的分区方式。

![Installation-Destination-Custom-CentOS8](/data/attachment/album/201910/09/121206cs7p325477n6wdyp.jpg)

点击“<ruby> 完成 <rt>  Done </rt></ruby>”。

如图所示，我为 CentOS 8 分配了 40 GB 的硬盘空间。有两种分区方案可供选择：如果由安装向导进行自动分区，可以从“<ruby> 存储配置 <rt>  Storage Configuration </rt></ruby>”中选择“<ruby> 自动 <rt>  Automatic </rt></ruby>”选项；如果想要自己手动进行分区，可以选择“<ruby> 自定义 <rt>  Custom </rt></ruby>”选项。

在这里我们选择“<ruby> 自定义 <rt>  Custom </rt></ruby>”选项，并按照以下的方式创建基于 LVM 的分区：

* `/boot` – 2 GB (ext4 文件系统)
* `/` – 12 GB (xfs 文件系统)
* `/home` – 20 GB (xfs 文件系统)
* `/tmp` – 5 GB (xfs 文件系统)
* Swap – 1 GB (xfs 文件系统)

首先创建 `/boot` 标准分区，设置大小为 2GB，如下图所示：

![boot-partition-CentOS8-Installation](/data/attachment/album/201910/09/121206q9t4oto94am49szt.jpg)

点击“<ruby> 添加挂载点 <rt>  Add mount point </rt></ruby>”。

再创建第二个分区 `/`，并设置大小为 12GB。点击加号，指定挂载点和分区大小，点击“<ruby> 添加挂载点 <rt>  Add mount point </rt></ruby>”即可。

![slash-root-partition-centos8-installation](/data/attachment/album/201910/09/121207oyi4oogd4dcphczd.jpg)

然后在页面上将 `/` 分区的分区类型从标准更改为 LVM，并点击“<ruby> 更新设置 <rt>  Update Settings </rt></ruby>”。

![Change-Partition-Type-CentOS8](/data/attachment/album/201910/09/121207fyxo93878mi7i7xy.jpg)

如上图所示，安装向导已经自动创建了一个卷组。如果想要更改卷组的名称，只需要点击“<ruby> 卷组 <rt>  Volume Group </rt></ruby>”标签页中的“<ruby> 修改 <rt>  Modify </rt></ruby>”选项。

同样地，创建 `/home` 分区和 `/tmp` 分区，分别将大小设置为 20GB 和 5GB，并设置分区类型为 LVM。

![home-partition-CentOS8-Installation](/data/attachment/album/201910/09/121208q8kzhhuyuz3ui8l8.jpg)

![tmp-partition-centos8-installation](/data/attachment/album/201910/09/121208k20ilel7qon2iddq.jpg)

最后创建<ruby> 交换分区 <rt>  Swap Partition </rt></ruby>。

![Swap-Partition-CentOS8-Installation](/data/attachment/album/201910/09/121209lrjngsgiganzttr2.jpg)

点击“<ruby> 添加挂载点 <rt>  Add mount point </rt></ruby>”。

在完成所有分区设置后，点击“<ruby> 完成 <rt>  Done </rt></ruby>”。

![Choose-Done-after-manual-partition-centos8](/data/attachment/album/201910/09/121209u930opgp386p3p9m.jpg)

在下一个界面，点击“<ruby> 应用更改 <rt>  Accept changes </rt></ruby>”，以上做的更改就会写入到硬盘中。

![Accept-changes-CentOS8-Installation](/data/attachment/album/201910/09/121211uwkri3puh3dhuh8u.jpg)

#### 第六步：选择“开始安装”

完成上述的所有更改后，回到先前的安装概览界面，点击“<ruby> 开始安装 <rt>  Begin Installation </rt></ruby>”以开始安装 CentOS 8。

![Begin-Installation-CentOS8](/data/attachment/album/201910/09/121211nk6hnlccu2ahc2xw.jpg)

下面这个界面表示安装过程正在进行中。

![Installation-progress-centos8](/data/attachment/album/201910/09/121211nt8jejvnjb9xnbht.jpg)

要设置 root 用户的口令，只需要点击 “<ruby> root 口令 <rt>  Root Password </rt></ruby>”选项，输入一个口令，然后点击“<ruby> 创建用户 <rt>  User Creation </rt></ruby>”选项创建一个本地用户。

![Root-Password-CentOS8-Installation](/data/attachment/album/201910/09/121212i6b635335of6h3up.jpg)

填写新创建的用户的详细信息。

![Local-User-Details-CentOS8](/data/attachment/album/201910/09/121212id94d9k9kju9j0tz.jpg)

在安装完成后，安装向导会提示重启系统。

![CentOS8-Installation-Progress](/data/attachment/album/201910/09/121213zl22jvs619sq6p6w.jpg)

#### 第七步：完成安装并重启系统

安装完成后要重启系统。只需点击“<ruby> 重启 <rt>  Reboot </rt></ruby>”按钮。

![Installation-Completed-CentOS8](/data/attachment/album/201910/09/121213zo84qfefagpr38q2.jpg)

注意：重启完成后，记得要把安装介质断开，并将 BIOS 的启动介质设置为硬盘。

#### 第八步：启动新安装的 CentOS 8 并接受许可协议

在 GRUB 引导菜单中，选择 CentOS 8 进行启动。

![Grub-Boot-CentOS8](/data/attachment/album/201910/09/121213rr1ys3h7r7r57x08.jpg)

同意 CentOS 8 的许可证，点击“<ruby> 完成 <rt>  Done </rt></ruby>”。

![Accept-License-CentOS8-Installation](/data/attachment/album/201910/09/121214x4dif5d5g64uu1su.jpg)

在下一个界面，点击“<ruby> 完成配置 <rt>  Finish Configuration </rt></ruby>”。

![Finish-Configuration-CentOS8-Installation](/data/attachment/album/201910/09/121214koqwuozbb9brogw8.jpg)

#### 第九步：配置完成后登录

同意 CentOS 8 的许可证以及完成配置之后，会来到登录界面。

![Login-screen-CentOS8](/data/attachment/album/201910/09/121215td78fmhb661ffl17.jpg)

使用刚才创建的用户以及对应的口令登录，按照提示进行操作，就可以看到以下界面。

![CentOS8-Ready-Use-Screen](/data/attachment/album/201910/09/121216fi9anhzio4pnnpnp.jpg)

点击“<ruby> 开始使用 CentOS Linux <rt>  Start Using CentOS Linux </rt></ruby>”。

![Desktop-Screen-CentOS8](/data/attachment/album/201910/09/121216c344z3khvh04kphe.jpg)

以上就是 CentOS 8 的安装过程，至此我们已经完成了 CentOS 8 的安装。

欢迎给我们发送评论。

---

via: <https://www.linuxtechi.com/centos-8-installation-guide-screenshots/>

作者：[Pradeep Kumar](https://www.linuxtechi.com/author/pradeep/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[HankChow](https://github.com/HankChow) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何通过 SSH 在远程 Linux 系统上运行命令

![](/data/attachment/album/201910/09/125518dcrqxqr5zb1q1qhf.jpg)

我们有时可能需要在远程机器上运行一些命令。如果只是偶尔进行的操作，要实现这个目的，可以登录到远程系统上直接执行命令。但是每次都这么做的话，就有点烦人了。既然如此，有没有摆脱这种麻烦操作的更佳方案？

是的，你可以从你本地系统上执行这些操作，而不用登录到远程系统上。这有什么好处吗？毫无疑问。这会为你节省很多好时光。

这是怎么实现的？SSH 允许你无需登录到远程计算机就可以在它上面运行命令。

**通用语法如下所示：**

```
$ ssh [用户名]@[远程主机名或 IP] [命令或脚本]
```

### 1) 如何通过 SSH 在远程 Linux 系统上运行命令

下面的例子允许用户通过 ssh 在远程 Linux 机器上运行 [df 命令](https://www.2daygeek.com/linux-check-disk-space-usage-df-command/)。

```
$ ssh daygeek@CentOS7.2daygeek.com df -h

 Filesystem               Size  Used Avail Use% Mounted on
 /dev/mapper/centos-root   27G  4.4G   23G  17% /
 devtmpfs                 903M     0  903M   0% /dev
 tmpfs                    920M     0  920M   0% /dev/shm
 tmpfs                    920M  9.3M  910M   2% /run
 tmpfs                    920M     0  920M   0% /sys/fs/cgroup
 /dev/sda1               1014M  179M  836M  18% /boot
 tmpfs                    184M  8.0K  184M   1% /run/user/42
 tmpfs                    184M     0  184M   0% /run/user/1000
```

### 2) 如何通过 SSH 在远程 Linux 系统上运行多条命令

下面的例子允许用户通过 ssh 在远程 Linux 机器上一次运行多条命令。

同时在远程 Linux 系统上运行 `uptime` 命令和 `free` 命令。

```
$ ssh daygeek@CentOS7.2daygeek.com "uptime && free -m"

 23:05:10 up 10 min,  0 users,  load average: 0.00, 0.03, 0.03

              total       used       free     shared    buffers     cached
 Mem:          1878        432       1445          1        100        134
 -/+ buffers/cache:        197       1680
 Swap:         3071          0       3071
```

### 3) 如何通过 SSH 在远程 Linux 系统上运行带 sudo 权限的命令

下面的例子允许用户通过 ssh 在远程 Linux 机器上运行带有 [sudo 权限](https://www.2daygeek.com/how-to-configure-sudo-access-in-linux/) 的 `fdisk` 命令。

普通用户不允许执行系统二进制（`/usr/sbin/`）目录下提供的命令。用户需要 root 权限来运行它。

所以你需要 root 权限，好在 Linux 系统上运行 [fdisk 命令](https://www.2daygeek.com/linux-fdisk-command-to-manage-disk-partitions/)。`which` 命令返回给定命令的完整可执行路径。

```
$ which fdisk
 /usr/sbin/fdisk
```

```
$ ssh -t daygeek@CentOS7.2daygeek.com "sudo fdisk -l"
 [sudo] password for daygeek:

 Disk /dev/sda: 32.2 GB, 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
 Disk label type: dos
 Disk identifier: 0x000bf685

 Device Boot      Start         End      Blocks   Id  System
 /dev/sda1   *        2048     2099199     1048576   83  Linux
 /dev/sda2         2099200    62914559    30407680   8e  Linux LVM

 Disk /dev/sdb: 10.7 GB, 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/mapper/centos-root: 29.0 GB, 28982640640 bytes, 56606720 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/mapper/centos-swap: 2147 MB, 2147483648 bytes, 4194304 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

 Connection to centos7.2daygeek.com closed.
```

### 4) 如何通过 SSH 在远程 Linux 系统上运行带 sudo 权限的服务控制命令

下面的例子允许用户通过 ssh 在远程 Linux 机器上运行带有 sudo 权限的服务控制命令。

```
$ ssh -t daygeek@CentOS7.2daygeek.com "sudo systemctl restart httpd"

 [sudo] password for daygeek:
 Connection to centos7.2daygeek.com closed.
```

### 5) 如何通过非标准端口 SSH 在远程 Linux 系统上运行命令

下面的例子允许用户通过 ssh 在使用了非标准端口的远程 Linux 机器上运行 [hostnamectl 命令](https://www.2daygeek.com/four-methods-to-change-the-hostname-in-linux/)。

```
$ ssh -p 2200 daygeek@CentOS7.2daygeek.com hostnamectl

    Static hostname: Ubuntu18.2daygeek.com
          Icon name: computer-vm
            Chassis: vm
         Machine ID: 27f6c2febda84dc881f28fd145077187
            Boot ID: bbeccdf932be41ddb5deae9e5f15183d
     Virtualization: oracle
   Operating System: Ubuntu 18.04.2 LTS
             Kernel: Linux 4.15.0-60-generic
       Architecture: x86-64
```

### 6) 如何将远程系统的输出保存到本地系统

下面的例子允许用户通过 ssh 在远程 Linux 机器上运行 [top 命令](https://www.2daygeek.com/understanding-linux-top-command-output-usage/)，并将输出保存到本地系统。

```
$ ssh daygeek@CentOS7.2daygeek.com "top -bc | head -n 35" > /tmp/top-output.txt
```

```
cat /tmp/top-output.txt

 top - 01:13:11 up 18 min,  1 user,  load average: 0.01, 0.05, 0.10
 Tasks: 168 total,   1 running, 167 sleeping,   0 stopped,   0 zombie
 %Cpu(s):  0.0 us,  6.2 sy,  0.0 ni, 93.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
 KiB Mem :  1882300 total,  1176324 free,   342392 used,   363584 buff/cache
 KiB Swap:  2097148 total,  2097148 free,        0 used.  1348140 avail Mem
 PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
  4943 daygeek   20   0  162052   2248   1612 R 10.0  0.1   0:00.07 top -bc
     1 root      20   0  128276   6936   4204 S  0.0  0.4   0:03.08 /usr/lib/sy+
     2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 [kthreadd]
     3 root      20   0       0      0      0 S  0.0  0.0   0:00.25 [ksoftirqd/+
     4 root      20   0       0      0      0 S  0.0  0.0   0:00.00 [kworker/0:+
     5 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [kworker/0:+
     7 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 [migration/+
     8 root      20   0       0      0      0 S  0.0  0.0   0:00.00 [rcu_bh]
     9 root      20   0       0      0      0 S  0.0  0.0   0:00.77 [rcu_sched]
    10 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [lru-add-dr+
    11 root      rt   0       0      0      0 S  0.0  0.0   0:00.01 [watchdog/0]
    13 root      20   0       0      0      0 S  0.0  0.0   0:00.00 [kdevtmpfs]
    14 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [netns]
    15 root      20   0       0      0      0 S  0.0  0.0   0:00.00 [khungtaskd]
    16 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [writeback]
    17 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [kintegrity+
    18 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [bioset]
    19 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [bioset]
    20 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 [bioset]
```

或者你也可以使用以下格式在远程系统上运行多条命令：

```
$ ssh daygeek@CentOS7.2daygeek.com << EOF
hostnamectl
free -m
grep daygeek /etc/passwd
EOF
```

上面命令的输出如下：

```
Pseudo-terminal will not be allocated because stdin is not a terminal.
    Static hostname: CentOS7.2daygeek.com
          Icon name: computer-vm
            Chassis: vm
         Machine ID: 002f47b82af248f5be1d67b67e03514c
            Boot ID: dca9a1ba06374d7d96678f9461752482
     Virtualization: kvm
   Operating System: CentOS Linux 7 (Core)
        CPE OS Name: cpe:/o:centos:centos:7
             Kernel: Linux 3.10.0-957.el7.x86_64
       Architecture: x86-64

               total        used        free      shared  buff/cache   available
 Mem:           1838         335        1146          11         355        1314
 Swap:          2047           0        2047

 daygeek:x:1000:1000:2daygeek:/home/daygeek:/bin/bash
```

### 7) 如何在远程系统上运行本地 Bash 脚本

下面的例子允许用户通过 ssh 在远程 Linux 机器上运行本地 [bash 脚本](https://www.2daygeek.com/understanding-linux-top-command-output-usage/) `remote-test.sh`。

创建一个 shell 脚本并执行它。

```
$ vi /tmp/remote-test.sh

#!/bin/bash
#Name: remote-test.sh
#--------------------
 uptime
 free -m
 df -h
 uname -a
 hostnamectl
```

上面命令的输出如下：

```
$ ssh daygeek@CentOS7.2daygeek.com 'bash -s' < /tmp/remote-test.sh

  01:17:09 up 22 min,  1 user,  load average: 0.00, 0.02, 0.08

               total        used        free      shared  buff/cache   available
 Mem:           1838         333        1148          11         355        1316
 Swap:          2047           0        2047

 Filesystem               Size  Used Avail Use% Mounted on
 /dev/mapper/centos-root   27G  4.4G   23G  17% /
 devtmpfs                 903M     0  903M   0% /dev
 tmpfs                    920M     0  920M   0% /dev/shm
 tmpfs                    920M  9.3M  910M   2% /run
 tmpfs                    920M     0  920M   0% /sys/fs/cgroup
 /dev/sda1               1014M  179M  836M  18% /boot
 tmpfs                    184M   12K  184M   1% /run/user/42
 tmpfs                    184M     0  184M   0% /run/user/1000

 Linux CentOS7.2daygeek.com 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

    Static hostname: CentOS7.2daygeek.com
          Icon name: computer-vm
            Chassis: vm
         Machine ID: 002f47b82af248f5be1d67b67e03514c
            Boot ID: dca9a1ba06374d7d96678f9461752482
     Virtualization: kvm
   Operating System: CentOS Linux 7 (Core)
        CPE OS Name: cpe:/o:centos:centos:7
             Kernel: Linux 3.10.0-957.el7.x86_64
       Architecture: x86-64
```

或者也可以使用管道。如果你觉得输出不太好看，再做点修改让它更优雅些。

```
$ vi /tmp/remote-test-1.sh

#!/bin/bash
#Name: remote-test.sh
 echo "---------System Uptime--------------------------------------------"
 uptime
 echo -e "\n"
 echo "---------Memory Usage---------------------------------------------"
 free -m
 echo -e "\n"
 echo "---------Disk Usage-----------------------------------------------"
 df -h
 echo -e "\n"
 echo "---------Kernel Version-------------------------------------------"
 uname -a
 echo -e "\n"
 echo "---------HostName Info--------------------------------------------"
 hostnamectl
 echo "------------------------------------------------------------------"
```

上面脚本的输出如下：

```
$ cat /tmp/remote-test.sh  | ssh daygeek@CentOS7.2daygeek.com
 Pseudo-terminal will not be allocated because stdin is not a terminal.
 ---------System Uptime--------------------------------------------
  03:14:09 up  2:19,  1 user,  load average: 0.00, 0.01, 0.05

 ---------Memory Usage---------------------------------------------
               total        used        free      shared  buff/cache   available
 Mem:           1838         376        1063          11         398        1253
 Swap:          2047           0        2047

 ---------Disk Usage-----------------------------------------------
 Filesystem               Size  Used Avail Use% Mounted on
 /dev/mapper/centos-root   27G  4.4G   23G  17% /
 devtmpfs                 903M     0  903M   0% /dev
 tmpfs                    920M     0  920M   0% /dev/shm
 tmpfs                    920M  9.3M  910M   2% /run
 tmpfs                    920M     0  920M   0% /sys/fs/cgroup
 /dev/sda1               1014M  179M  836M  18% /boot
 tmpfs                    184M   12K  184M   1% /run/user/42
 tmpfs                    184M     0  184M   0% /run/user/1000
 tmpfs                    184M     0  184M   0% /run/user/0

 ---------Kernel Version-------------------------------------------
 Linux CentOS7.2daygeek.com 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

 ---------HostName Info--------------------------------------------
    Static hostname: CentOS7.2daygeek.com
          Icon name: computer-vm
            Chassis: vm
         Machine ID: 002f47b82af248f5be1d67b67e03514c
            Boot ID: dca9a1ba06374d7d96678f9461752482
     Virtualization: kvm
   Operating System: CentOS Linux 7 (Core)
        CPE OS Name: cpe:/o:centos:centos:7
             Kernel: Linux 3.10.0-957.el7.x86_64
       Architecture: x86-64
```

### 8) 如何同时在多个远程系统上运行多条指令

下面的 bash 脚本允许用户同时在多个远程系统上运行多条指令。使用简单的 `for` 循环实现。

为了实现这个目的，你可以尝试 [PSSH 命令](https://www.2daygeek.com/pssh-parallel-ssh-run-execute-commands-on-multiple-linux-servers/) 或 [ClusterShell 命令](https://www.2daygeek.com/clustershell-clush-run-commands-on-cluster-nodes-remote-system-in-parallel-linux/) 或 [DSH 命令](https://www.2daygeek.com/dsh-run-execute-shell-commands-on-multiple-linux-servers-at-once/)。

```
$ vi /tmp/multiple-host.sh

 for host in CentOS7.2daygeek.com CentOS6.2daygeek.com
 do
    ssh daygeek@${host} "uname -a;uptime;date;w"
 done
```

上面脚本的输出如下：

```
$ sh multiple-host.sh

 Linux CentOS7.2daygeek.com 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

  01:33:57 up 39 min,  1 user,  load average: 0.07, 0.06, 0.06

 Wed Sep 25 01:33:57 CDT 2019

  01:33:57 up 39 min,  1 user,  load average: 0.07, 0.06, 0.06
 USER     TTY      FROM             daygeek@CentOS7.2daygeek.com   IDLE   JCPU   PCPU WHAT
 daygeek  pts/0    192.168.1.6      01:08   23:25   0.06s  0.06s -bash

 Linux CentOS6.2daygeek.com 2.6.32-754.el6.x86_64 #1 SMP Tue Jun 19 21:26:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

  23:33:58 up 39 min,  0 users,  load average: 0.00, 0.00, 0.00

 Tue Sep 24 23:33:58 MST 2019

  23:33:58 up 39 min,  0 users,  load average: 0.00, 0.00, 0.00
 USER     TTY      FROM             daygeek@CentOS7.2daygeek.com   IDLE   JCPU   PCPU WHAT
```

### 9) 如何使用 sshpass 命令添加一个密码

如果你觉得每次输入密码很麻烦，我建议你视你的需求选择以下方法中的一项来解决这个问题。

如果你经常进行类似的操作，我建议你设置 [免密码认证](https://www.2daygeek.com/configure-setup-passwordless-ssh-key-based-authentication-linux/)，因为它是标准且永久的解决方案。

如果你一个月只是执行几次这些任务，我推荐你使用 `sshpass` 工具。只需要使用 `-p` 参数选项提供你的密码即可。

```
$ sshpass -p '在这里输入你的密码' ssh -p 2200 daygeek@CentOS7.2daygeek.com ip a

 1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
     inet 127.0.0.1/8 scope host lo
        valid_lft forever preferred_lft forever
     inet6 ::1/128 scope host
        valid_lft forever preferred_lft forever
 2: eth0:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
     link/ether 08:00:27:18:90:7f brd ff:ff:ff:ff:ff:ff
     inet 192.168.1.12/24 brd 192.168.1.255 scope global dynamic eth0
        valid_lft 86145sec preferred_lft 86145sec
     inet6 fe80::a00:27ff:fe18:907f/64 scope link tentative dadfailed
        valid_lft forever preferred_lft forever
```

---

via: <https://www.2daygeek.com/execute-run-linux-commands-remote-system-over-ssh/>

作者：[Magesh Maruthamuthu](https://www.2daygeek.com/author/magesh/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出