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

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

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

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

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

`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` 命令中使用的不同选项：

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

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

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

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

以上内容确认了我们在终端上执行的所有命令都已保存在 `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
```

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

### 记录所有用户的 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]#
```

我们还可以使用 `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 技巧

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

我在编程教学方面不是专家，但当我想更好掌握某一样东西时，会试着找出让自己乐在其中的方法。比方说，当我想在 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]` 为行。

### 创建玩家逻辑

玩家操作背后的逻辑在于，先从 [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
}
```

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

还记得我们开头定义的变量，`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
```

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

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

这个程序需要记录游戏界面中哪些单元格是可选择的。否则，程序会一直让用户输入数据，即使所有单元格都被选中过。为了实现这一功能，我创建了一个叫 `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
```

文章到这里就结束了，朋友们！如果你想了解更多，具体可以查看我的 [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 中的数据里的漏洞。

# 4 种开源云安全工具

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

<img src="content_image/album_201910_07_140417vhywycwwdoakzyqi.jpg" alt="" title="">

如果你的日常工作是开发者、系统管理员、全栈工程师或者是网站可靠性工程师（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 也可以吗？

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

[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 体验

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

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

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

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

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

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

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

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

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

最后，就这样完成了。

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

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

### 总结

总的来说，对于希望在 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 的开源应用从你的电脑上访问你的安卓设备。

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

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

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

虽然不完全是像全息终端或飞行汽车那样酷炫，但 [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 作为说明的，你的不同品牌的安卓手机打开开发者选项的方式或有不同。）

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

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

### 使用 Guiscrcpy

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

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

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

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

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

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。

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

# 我买了一台 Linux 笔记本

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

最近，我开始使用我买的 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 键上印上一个企鹅图标！我需要的西班牙语键盘则不提供此选项。

### 收货并开箱使用

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

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

该电脑的设计确实很棒，而且感觉扎实。即使此型号的外壳不是铝制的（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: 阿里云正在云原生的路上狂奔，将各个产品、服务都押宝在元原生的领域上。

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

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

### 云原生是什么？

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

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

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

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

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

### 云原生进化

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

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

这次云栖大会上阿里云还发布了 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 还是安全沙箱，两种容器运行时用户体验是完全一致的，用户可以根据自己对业务需求来选择合适的容器应用技术。

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

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

### 结语

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


CentOS 8 安装图解

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

新手入门

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

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

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

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

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

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

写的很详细，优秀的

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

# CentOS 8 安装图解

继 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）选项并按回车。

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

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

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

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

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

如上图所示，安装向导已经自动提供了“<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>”即可。

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

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

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

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

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

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

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

点击“<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，如下图所示：

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

以上就是 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 系统上运行命令

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

<img src="content_image/album_201910_09_125518dcrqxqr5zb1q1qhf.jpg" alt="" title="">

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

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

这是怎么实现的？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/) 荣誉推出


GNU binutils 里的九种武器

Summary: 二进制分析是计算机行业中最被低估的技能。

不错，很详细。解答了我的一些问题

不错，很详细。解答了我的一些问题

二进制分析是计算机行业中最被低估的技能。

# GNU binutils 里的九种武器

>
> 二进制分析是计算机行业中最被低估的技能。
>
>
>

<img src="content_image/album_201910_10_115409g9nkdm2omutduw7u.jpg" alt="" title="">

想象一下，在无法访问软件的源代码时，但仍然能够理解软件的实现方式，在其中找到漏洞，并且更厉害的是还能修复错误。所有这些都是在只有二进制文件时做到的。这听起来就像是超能力，对吧？

你也可以拥有这样的超能力，GNU 二进制实用程序（binutils）就是一个很好的起点。[GNU binutils](https://en.wikipedia.org/wiki/GNU_Binutils) 是一个二进制工具集，默认情况下所有 Linux 发行版中都会安装这些二进制工具。

二进制分析是计算机行业中最被低估的技能。它主要由恶意软件分析师、反向工程师和使用底层软件的人使用。

本文探讨了 binutils 可用的一些工具。我使用的是 RHEL，但是这些示例应该在任何 Linux 发行版上可以运行。

```
[~]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.6 (Maipo)
[~]#
[~]# uname -r
3.10.0-957.el7.x86_64
[~]#
```

请注意，某些打包命令（例如 `rpm`）在基于 Debian 的发行版中可能不可用，因此请使用等效的 `dpkg` 命令替代。

### 软件开发的基础知识

在开源世界中，我们很多人都专注于源代码形式的软件。当软件的源代码随时可用时，很容易获得源代码的副本，打开喜欢的编辑器，喝杯咖啡，然后就可以开始探索了。

但是源代码不是在 CPU 上执行的代码，在 CPU 上执行的是二进制或者说是机器语言指令。二进制或可执行文件是编译源代码时获得的。熟练的调试人员深谙通常这种差异。

### 编译的基础知识

在深入研究 binutils 软件包本身之前，最好先了解编译的基础知识。

编译是将程序从某种编程语言（如 C/C++）的源代码（文本形式）转换为机器代码的过程。

机器代码是 CPU（或一般而言，硬件）可以理解的 1 和 0 的序列，因此可以由 CPU 执行或运行。该机器码以特定格式保存到文件，通常称为可执行文件或二进制文件。在 Linux（和使用 [Linux 兼容二进制](https://www.freebsd.org/doc/handbook/linuxemu.html)的 BSD）上，这称为 [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)（<ruby> 可执行和可链接格式 <rt>  Executable and Linkable Format </rt></ruby>）。

在生成给定的源文件的可执行文件或二进制文件之前，编译过程将经历一系列复杂的步骤。以这个源程序（C 代码）为例。打开你喜欢的编辑器，然后键入以下程序：

```
#include <stdio.h>

int main(void)
{
  printf("Hello World\n");
  return 0;
}
```

#### 步骤 1：用 cpp 预处理

[C 预处理程序（cpp）](https://en.wikipedia.org/wiki/C_preprocessor)用于扩展所有宏并将头文件包含进来。在此示例中，头文件 `stdio.h` 将被包含在源代码中。`stdio.h` 是一个头文件，其中包含有关程序内使用的 `printf` 函数的信息。对源代码运行 `cpp`，其结果指令保存在名为 `hello.i` 的文件中。可以使用文本编辑器打开该文件以查看其内容。打印 “hello world” 的源代码在该文件的底部。

```
[testdir]# cat hello.c
#include <stdio.h>

int main(void)
{
  printf("Hello World\n");
  return 0;
}
[testdir]#
[testdir]# cpp hello.c > hello.i
[testdir]#
[testdir]# ls -lrt
total 24
-rw-r--r--. 1 root root 76 Sep 13 03:20 hello.c
-rw-r--r--. 1 root root 16877 Sep 13 03:22 hello.i
[testdir]#
```

#### 步骤 2：用 gcc 编译

在此阶段，无需创建目标文件就将步骤 1 中生成的预处理源代码转换为汇编语言指令。这个阶段使用 [GNU 编译器集合（gcc）](https://gcc.gnu.org/onlinedocs/gcc/)。对 `hello.i` 文件运行带有 `-S` 选项的 `gcc` 命令后，它将创建一个名为 `hello.s` 的新文件。该文件包含该 C 程序的汇编语言指令。

你可以使用任何编辑器或 `cat` 命令查看其内容。

```
[testdir]#
[testdir]# gcc -Wall -S hello.i
[testdir]#
[testdir]# ls -l
total 28
-rw-r--r--. 1 root root 76 Sep 13 03:20 hello.c
-rw-r--r--. 1 root root 16877 Sep 13 03:22 hello.i
-rw-r--r--. 1 root root 448 Sep 13 03:25 hello.s
[testdir]#
[testdir]# cat hello.s
.file "hello.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)"
.section .note.GNU-stack,"",@progbits
[testdir]#
```

#### 步骤 3：用 as 汇编

汇编器的目的是将汇编语言指令转换为机器语言代码，并生成扩展名为 `.o` 的目标文件。此阶段使用默认情况下在所有 Linux 平台上都可用的 GNU 汇编器。

```
testdir]# as hello.s -o hello.o
[testdir]#
[testdir]# ls -l
total 32
-rw-r--r--. 1 root root 76 Sep 13 03:20 hello.c
-rw-r--r--. 1 root root 16877 Sep 13 03:22 hello.i
-rw-r--r--. 1 root root 1496 Sep 13 03:39 hello.o
-rw-r--r--. 1 root root 448 Sep 13 03:25 hello.s
[testdir]#
```

现在，你有了第一个 ELF 格式的文件；但是，还不能执行它。稍后，你将看到“<ruby> 目标文件 <rt>  object file </rt></ruby>”和“<ruby> 可执行文件 <rt>  executable file </rt></ruby>”之间的区别。

```
[testdir]# file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
```

#### 步骤 4：用 ld 链接

这是编译的最后阶段，将目标文件链接以创建可执行文件。可执行文件通常需要外部函数，这些外部函数通常来自系统库（`libc`）。

你可以使用 `ld` 命令直接调用链接器；但是，此命令有些复杂。相反，你可以使用带有 `-v`（详细）标志的 `gcc` 编译器，以了解链接是如何发生的。（使用 `ld` 命令进行链接作为一个练习，你可以自行探索。）

```
[testdir]# gcc -v hello.o
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man [...] --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:[...]:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu [...]/../../../../lib64/crtn.o
[testdir]#
```

运行此命令后，你应该看到一个名为 `a.out` 的可执行文件：

```
[testdir]# ls -l
total 44
-rwxr-xr-x. 1 root root 8440 Sep 13 03:45 a.out
-rw-r--r--. 1 root root 76 Sep 13 03:20 hello.c
-rw-r--r--. 1 root root 16877 Sep 13 03:22 hello.i
-rw-r--r--. 1 root root 1496 Sep 13 03:39 hello.o
-rw-r--r--. 1 root root 448 Sep 13 03:25 hello.s
```

对 `a.out` 运行 `file` 命令，结果表明它确实是 ELF 可执行文件：

```
[testdir]# file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=48e4c11901d54d4bf1b6e3826baf18215e4255e5, not stripped
```

运行该可执行文件，看看它是否如源代码所示工作：

```
[testdir]# ./a.out Hello World
```

工作了！在幕后发生了很多事情它才在屏幕上打印了 “Hello World”。想象一下在更复杂的程序中会发生什么。

### 探索 binutils 工具

上面这个练习为使用 binutils 软件包中的工具提供了良好的背景。我的系统带有 binutils 版本 2.27-34；你的 Linux 发行版上的版本可能有所不同。

```
[~]# rpm -qa | grep binutils
binutils-2.27-34.base.el7.x86_64
```

binutils 软件包中提供了以下工具：

```
[~]# rpm -ql binutils-2.27-34.base.el7.x86_64 | grep bin/
/usr/bin/addr2line
/usr/bin/ar
/usr/bin/as
/usr/bin/c++filt
/usr/bin/dwp
/usr/bin/elfedit
/usr/bin/gprof
/usr/bin/ld
/usr/bin/ld.bfd
/usr/bin/ld.gold
/usr/bin/nm
/usr/bin/objcopy
/usr/bin/objdump
/usr/bin/ranlib
/usr/bin/readelf
/usr/bin/size
/usr/bin/strings
/usr/bin/strip
```

上面的编译练习已经探索了其中的两个工具：用作汇编器的 `as` 命令，用作链接器的 `ld` 命令。继续阅读以了解上述 GNU binutils 软件包工具中的其他七个。

#### readelf：显示 ELF 文件信息

上面的练习提到了术语“目标文件”和“可执行文件”。使用该练习中的文件，通过带有 `-h`（标题）选项的 `readelf` 命令，以将文件的 ELF 标题转储到屏幕上。请注意，以 `.o` 扩展名结尾的目标文件显示为 `Type: REL (Relocatable file)`（可重定位文件）：

```
[testdir]# readelf -h hello.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 [...]
[...]
Type: REL (Relocatable file)
[...]
```

如果尝试执行此目标文件，会收到一条错误消息，指出无法执行。这仅表示它尚不具备在 CPU 上执行所需的信息。

请记住，你首先需要使用 `chmod` 命令在对象文件上添加 `x`（可执行位），否则你将得到“权限被拒绝”的错误。

```
[testdir]# ./hello.o
bash: ./hello.o: Permission denied
[testdir]# chmod +x ./hello.o
[testdir]#
[testdir]# ./hello.o
bash: ./hello.o: cannot execute binary file
```

如果对 `a.out` 文件尝试相同的命令，则会看到其类型为 `EXEC (Executable file)`（可执行文件）。

```
[testdir]# readelf -h a.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
[...] Type: EXEC (Executable file)
```

如上所示，该文件可以直接由 CPU 执行：

```
[testdir]# ./a.out Hello World
```

`readelf` 命令可提供有关二进制文件的大量信息。在这里，它会告诉你它是 ELF 64 位格式，这意味着它只能在 64 位 CPU 上执行，而不能在 32 位 CPU 上运行。它还告诉你它应在 X86-64（Intel/AMD）架构上执行。该二进制文件的入口点是地址 `0x400430`，它就是 C 源程序中 `main` 函数的地址。

在你知道的其他系统二进制文件上尝试一下 `readelf` 命令，例如 `ls`。请注意，在 RHEL 8 或 Fedora 30 及更高版本的系统上，由于安全原因改用了<ruby> 位置无关可执行文件 <rt>  position independent executable </rt></ruby>（[PIE](https://en.wikipedia.org/wiki/Position-independent_code#Position-independent_executables)），因此你的输出（尤其是 `Type:`）可能会有所不同。

```
[testdir]# readelf -h /bin/ls
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
```

使用 `ldd` 命令了解 `ls` 命令所依赖的系统库，如下所示：

```
[testdir]# ldd /bin/ls
linux-vdso.so.1 => (0x00007ffd7d746000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f060daca000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007f060d8c5000)
libacl.so.1 => /lib64/libacl.so.1 (0x00007f060d6bc000)
libc.so.6 => /lib64/libc.so.6 (0x00007f060d2ef000)
libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f060d08d000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f060ce89000)
/lib64/ld-linux-x86-64.so.2 (0x00007f060dcf1000)
libattr.so.1 => /lib64/libattr.so.1 (0x00007f060cc84000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f060ca68000)
```

对 `libc` 库文件运行 `readelf` 以查看它是哪种文件。正如它指出的那样，它是一个 `DYN (Shared object file)`（共享对象文件），这意味着它不能直接执行；必须由内部使用了该库提供的任何函数的可执行文件使用它。

```
[testdir]# readelf -h /lib64/libc.so.6
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: DYN (Shared object file)
```

#### size：列出节的大小和全部大小

`size` 命令仅适用于目标文件和可执行文件，因此，如果尝试在简单的 ASCII 文件上运行它，则会抛出错误，提示“文件格式无法识别”。

```
[testdir]# echo "test" > file1
[testdir]# cat file1
test
[testdir]# file file1
file1: ASCII text
[testdir]# size file1
size: file1: File format not recognized
```

现在，在上面的练习中，对目标文件和可执行文件运行 `size` 命令。请注意，根据 `size` 命令的输出可以看出，可执行文件（`a.out`）的信息要比目标文件（`hello.o`）多得多：

```
[testdir]# size hello.o
text data bss dec hex filename
89 0 0 89 59 hello.o
[testdir]# size a.out
text data bss dec hex filename
1194 540 4 1738 6ca a.out
```

但是这里的 `text`、`data` 和 `bss` 节是什么意思？

`text` 节是指二进制文件的代码部分，其中包含所有可执行指令。`data` 节是所有初始化数据所在的位置，`bss` 节是所有未初始化数据的存储位置。（LCTT 译注：一般来说，在静态的映像文件中，各个部分称之为<ruby> 节 <rt>  section </rt></ruby>，而在运行时的各个部分称之为<ruby> 段 <rt>  segment </rt></ruby>，有时统称为段。）

比较其他一些可用的系统二进制文件的 `size` 结果。

对于 `ls` 命令：

```
[testdir]# size /bin/ls
text data bss dec hex filename
103119 4768 3360 111247 1b28f /bin/ls
```

只需查看 `size` 命令的输出，你就可以看到 `gcc` 和 `gdb` 是比 `ls` 大得多的程序：

```
[testdir]# size /bin/gcc
text data bss dec hex filename
755549 8464 81856 845869 ce82d /bin/gcc
[testdir]# size /bin/gdb
text data bss dec hex filename
6650433 90842 152280 6893555 692ff3 /bin/gdb
```

#### strings：打印文件中的可打印字符串

在 `strings` 命令中添加 `-d` 标志以仅显示 `data` 节中的可打印字符通常很有用。

`hello.o` 是一个目标文件，其中包含打印出 `Hello World` 文本的指令。因此，`strings` 命令的唯一输出是 `Hello World`。

```
[testdir]# strings -d hello.o
Hello World
```

另一方面，在 `a.out`（可执行文件）上运行 `strings` 会显示在链接阶段该二进制文件中包含的其他信息：

```
[testdir]# strings -d a.out
/lib64/ld-linux-x86-64.so.2
!^BU
libc.so.6
puts
__libc_start_main
__gmon_start__
GLIBC_2.2.5
UH-0
UH-0
=(
[]A\A]A^A_
Hello World
;*3$"
```

#### objdump：显示目标文件信息

另一个可以从二进制文件中转储机器语言指令的 binutils 工具称为 `objdump`。使用 `-d` 选项，可从二进制文件中反汇编出所有汇编指令。

回想一下，编译是将源代码指令转换为机器代码的过程。机器代码仅由 1 和 0 组成，人类难以阅读。因此，它有助于将机器代码表示为汇编语言指令。汇编语言是什么样的？请记住，汇编语言是特定于体系结构的；由于我使用的是 Intel（x86-64）架构，因此如果你使用 ARM 架构编译相同的程序，指令将有所不同。

```
[testdir]# objdump -d hello.o
hello.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000
:
0:  55              push %rbp
1:  48 89 e5        mov %rsp,%rbp
4:  bf 00 00 00 00  mov $0x0,%edi
9:  e8 00 00 00 00  callq e

e:  b8 00 00 00 00  mov $0x0,%eax
13: 5d              pop %rbp
14: c3              retq
```

该输出乍一看似乎令人生畏，但请花一点时间来理解它，然后再继续。回想一下，`.text` 节包含所有的机器代码指令。汇编指令可以在第四列中看到（即 `push`、`mov`、`callq`、`pop`、`retq` 等）。这些指令作用于寄存器，寄存器是 CPU 内置的存储器位置。本示例中的寄存器是 `rbp`、`rsp`、`edi`、`eax` 等，并且每个寄存器都有特殊的含义。

现在对可执行文件（`a.out`）运行 `objdump` 并查看得到的内容。可执行文件的 `objdump` 的输出可能很大，因此我使用 `grep` 命令将其缩小到 `main` 函数：

```
[testdir]# objdump -d a.out | grep -A 9 main\>
000000000040051d
:
40051d: 55              push %rbp
40051e: 48 89 e5        mov %rsp,%rbp
400521: bf d0 05 40 00  mov $0x4005d0,%edi
400526: e8 d5 fe ff ff  callq 400400
40052b: b8 00 00 00 00  mov $0x0,%eax
400530: 5d              pop %rbp
400531: c3              retq
```

请注意，这些指令与目标文件 `hello.o` 相似，但是其中包含一些其他信息：

* 目标文件 `hello.o` 具有以下指令：`callq e`
* 可执行文件 `a.out` 由以下指令组成，该指令带有一个地址和函数：`callq 400400 <puts@plt>` 上面的汇编指令正在调用 `puts` 函数。请记住，你在源代码中使用了一个 `printf` 函数。编译器插入了对 `puts` 库函数的调用，以将 `Hello World` 输出到屏幕。

查看 `put` 上方一行的说明：

* 目标文件 `hello.o` 有个指令 `mov`：`mov $0x0,%edi`
* 可执行文件 `a.out` 的 `mov` 指令带有实际地址（`$0x4005d0`）而不是 `$0x0`：`mov $0x4005d0,%edi`

该指令将二进制文件中地址 `$0x4005d0` 处存在的内容移动到名为 `edi` 的寄存器中。

这个存储位置的内容中还能是别的什么吗？是的，你猜对了：它就是文本 `Hello, World`。你是如何确定的？

`readelf` 命令使你可以将二进制文件（`a.out`）的任何节转储到屏幕上。以下要求它将 `.rodata`（这是只读数据）转储到屏幕上：

```
[testdir]# readelf -x .rodata a.out

Hex dump of section '.rodata':
0x004005c0 01000200 00000000 00000000 00000000 ....
0x004005d0 48656c6c 6f20576f 726c6400 Hello World.
```

你可以在右侧看到文本 `Hello World`，在左侧可以看到其二进制格式的地址。它是否与你在上面的 `mov` 指令中看到的地址匹配？是的，确实匹配。

#### strip：从目标文件中剥离符号

该命令通常用于在将二进制文件交付给客户之前减小二进制文件的大小。

请记住，由于重要信息已从二进制文件中删除，因此它会妨碍调试。但是，这个二进制文件可以完美地执行。

对 `a.out` 可执行文件运行该命令，并注意会发生什么。首先，通过运行以下命令确保二进制文件没有被剥离（`not stripped`）：

```
[testdir]# file a.out
a.out: ELF 64-bit LSB executable, x86-64, [......] not stripped
```

另外，在运行 `strip` 命令之前，请记下二进制文件中最初的字节数：

```
[testdir]# du -b a.out
8440 a.out
```

现在对该可执行文件运行 `strip` 命令，并使用 `file` 命令以确保正常完成：

```
[testdir]# strip a.out
[testdir]# file a.out a.out: ELF 64-bit LSB executable, x86-64, [......] stripped

```

剥离该二进制文件后，此小程序的大小从之前的 `8440` 字节减小为 `6296` 字节。对于这样小的一个程序都能有这么大的空间节省，难怪大型程序经常被剥离。

```
[testdir]# du -b a.out
6296 a.out
```

#### addr2line：转换地址到文件名和行号

`addr2line` 工具只是在二进制文件中查找地址，并将其与 C 源代码程序中的行进行匹配。很酷，不是吗？

为此编写另一个测试程序；只是这一次确保使用 `gcc` 的 `-g` 标志进行编译，这将为二进制文件添加其它调试信息，并包含有助于调试的行号（由源代码中提供）：

```
[testdir]# cat -n atest.c
1  #include <stdio.h>
2
3  int globalvar = 100;
4
5  int function1(void)
6  {
7    printf("Within function1\n");
8    return 0;
9  }
10
11 int function2(void)
12 {
13   printf("Within function2\n");
14   return 0;
15 }
16
17 int main(void)
18 {
19   function1();
20   function2();
21   printf("Within main\n");
22   return 0;
23 }
```

用 `-g` 标志编译并执行它。正如预期：

```
[testdir]# gcc -g atest.c
[testdir]# ./a.out
Within function1
Within function2
Within main
```

现在使用 `objdump` 来标识函数开始的内存地址。你可以使用 `grep` 命令来过滤出所需的特定行。函数的地址在下面突出显示（`55 push %rbp` 前的地址）：

```
[testdir]# objdump -d a.out | grep -A 2 -E 'main>:|function1>:|function2>:'
000000000040051d :
40051d: 55 push %rbp
40051e: 48 89 e5 mov %rsp,%rbp
--
0000000000400532 :
400532: 55 push %rbp
400533: 48 89 e5 mov %rsp,%rbp
--
0000000000400547
:
400547: 55 push %rbp
400548: 48 89 e5 mov %rsp,%rbp
```

现在，使用 `addr2line` 工具从二进制文件中的这些地址映射到 C 源代码匹配的地址：

```
[testdir]# addr2line -e a.out 40051d
/tmp/testdir/atest.c:6
[testdir]#
[testdir]# addr2line -e a.out 400532
/tmp/testdir/atest.c:12
[testdir]#
[testdir]# addr2line -e a.out 400547
/tmp/testdir/atest.c:18
```

它说 `40051d` 从源文件 `atest.c` 中的第 `6` 行开始，这是 `function1` 的起始大括号（`{`）开始的行。`function2` 和 `main` 的输出也匹配。

#### nm：列出目标文件的符号

使用上面的 C 程序测试 `nm` 工具。使用 `gcc` 快速编译并执行它。

```
[testdir]# gcc atest.c
[testdir]# ./a.out
Within function1
Within function2
Within main
```

现在运行 `nm` 和 `grep` 获取有关函数和变量的信息：

```
[testdir]# nm a.out | grep -Ei 'function|main|globalvar'
000000000040051d T function1
0000000000400532 T function2
000000000060102c D globalvar
U __libc_start_main@@GLIBC_2.2.5
0000000000400547 T main
```

你可以看到函数被标记为 `T`，它表示 `text` 节中的符号，而变量标记为 `D`，表示初始化的 `data` 节中的符号。

想象一下在没有源代码的二进制文件上运行此命令有多大用处？这使你可以窥视内部并了解使用了哪些函数和变量。当然，除非二进制文件已被剥离，这种情况下它们将不包含任何符号，因此 `nm` 就命令不会很有用，如你在此处看到的：

```
[testdir]# strip a.out
[testdir]# nm a.out | grep -Ei 'function|main|globalvar'
nm: a.out: no symbols
```

### 结论

GNU binutils 工具为有兴趣分析二进制文件的人提供了许多选项，这只是它们可以为你做的事情的冰山一角。请阅读每种工具的手册页，以了解有关它们以及如何使用它们的更多信息。

---

via: <https://opensource.com/article/19/10/gnu-binutils>

作者：[Gaurav Kamathe](https://opensource.com/users/gkamathe) 选题：[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/) 荣誉推出


IceWM：一个非常酷的桌面

# IceWM：一个非常酷的桌面

IceWM 是一款非常轻量的桌面。它已经出现 20 多年了，它今天的目标仍然与当时相同：速度、简单性以及不妨碍用户。

我曾经将 IceWM 添加到 Scientific Linux 中作为轻量级桌面。当时它只是 0.5 兆的 rpm 包。运行时，它仅使用 5 兆的内存。这些年来，IceWM 有所增长。rpm 包现在为 1 兆。运行时，IceWM 现在使用 10 兆的内存。尽管在过去十年中它的大小增加了一倍，但它仍然非常小。

这么小的包，你能得到什么？确切地说，就是一个窗口管理器。没有其他东西。你有一个带有菜单或图标的工具栏来启动程序。速度很快。最后，还有主题和选项。除了工具栏中的一些小东西，就只有这些了。

### 安装

因为 IceWM 很小，你只需安装主软件包。

```
$ sudo dnf install icewm
```

如果要节省磁盘空间，许多依赖项都是可选的。没有它们，IceWM 也可以正常工作。

```
$ sudo dnf install icewm --setopt install_weak_deps=false
```

### 选项

IceWM 默认已经设置完毕，以使普通的 Windows 用户也能感到舒适。这是一件好事，因为选项是通过配置文件手动完成的。

我希望你不会因此而止步，因为它并没有听起来那么糟糕。它只有 8 个配置文件，大多数人只使用其中几个。主要的三个配置文件是 `keys`（键绑定），`preferences`（总体首选项）和 `toolbar`（工具栏上显示的内容）。默认配置文件位于 `/usr/share/icewm/`。

要进行更改，请将默认配置复制到 IceWM 家目录（`~/.icewm`），编辑文件，然后重新启动 IceWM。第一次做可能会有点害怕，因为在 “Logout” 菜单项下可以找到 “Restart Icewm”。但是，当你重启 IceWM 时，你只会看到闪烁一下，更改就生效了。任何打开的程序均不受影响，并保持原样。

### 主题

如果安装 icewm-themes 包，那么会得到很多主题。与常规选项不同，你无需重启 IceWM 即可更改为新主题。通常我不会谈论主题，但是由于其他功能很少，因此我想提下。

### 工具栏

工具栏是为 IceWM 添加了更多的功能的地方。你可以看到它可以切换不同的工作区。工作区有时称为虚拟桌面。单击工作区图标以移动到它。右键单击一个窗口的任务栏项目，可以在工作区之间移动它。如果你喜欢工作区，它拥有你想要的所有功能。如果你不喜欢工作区，那么可以选择关闭它。

工具栏还有网络/内存/CPU 监控图。将鼠标悬停在图标上可获得详细信息。单击图标可以打开一个拥有完整监控功能的窗口。这些小图形曾经出现在每个窗口管理器上。但是，随着桌面环境的成熟，它们都将这些图形去除了。我很高兴 IceWM 留下了这个不错的功能。

### 总结

如果你想要轻量但功能强大的桌面，IceWM 适合你。它已经设置好了，因此新的 Linux 用户也可以立即使用它。它是灵活的，因此 Unix 用户可以根据自己的喜好进行调整。最重要的是，IceWM 可以让你的程序不受阻碍地运行。

---

via: <https://fedoramagazine.org/icewm-a-really-cool-desktop/>

作者：[tdawson](https://fedoramagazine.org/author/tdawson/) 选题：[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/) 荣誉推出


安全强化你的 Linux 服务器的七个步骤

Summary: 通过七个简单的步骤来加固你的 Linux 服务器。

通过七个简单的步骤来加固你的 Linux 服务器。

# 安全强化你的 Linux 服务器的七个步骤

>
> 通过七个简单的步骤来加固你的 Linux 服务器。
>
>
>

<img src="content_image/album_201910_11_094107k8skl8wwxq62pzld.jpg" alt="" title="">

这篇入门文章将向你介绍基本的 Linux 服务器安全知识。虽然主要针对 Debian/Ubuntu，但是你可以将此处介绍的所有内容应用于其他 Linux 发行版。我也鼓励你研究这份材料，并在适用的情况下进行扩展。

### 1、更新你的服务器

保护服务器安全的第一件事是更新本地存储库，并通过应用最新的修补程序来升级操作系统和已安装的应用程序。

在 Ubuntu 和 Debian 上：

```
$ sudo apt update && sudo apt upgrade -y
```

在 Fedora、CentOS 或 RHEL：

```
$ sudo dnf upgrade
```

### 2、创建一个新的特权用户

接下来，创建一个新的用户帐户。永远不要以 root 身份登录服务器，而是创建你自己的帐户（用户），赋予它 `sudo` 权限，然后使用它登录你的服务器。

首先创建一个新用户：

```
$ adduser <username>
```

通过将 `sudo` 组（`-G`）附加（`-a`）到用户的组成员身份里，从而授予新用户帐户 `sudo` 权限：

```
$ usermod -a -G sudo <username>
```

### 3、上传你的 SSH 密钥

你应该使用 SSH 密钥登录到新服务器。你可以使用 `ssh-copy-id` 命令将[预生成的 SSH 密钥](https://opensource.com/article/19/4/ssh-keys-seahorse)上传到你的新服务器：

```
$ ssh-copy-id <username>@ip_address
```

现在，你无需输入密码即可登录到新服务器。

### 4、安全强化 SSH

接下来，进行以下三个更改：

* 禁用 SSH 密码认证
* 限制 root 远程登录
* 限制对 IPv4 或 IPv6 的访问

使用你选择的文本编辑器打开 `/etc/ssh/sshd_config` 并确保以下行：

```
PasswordAuthentication yes
PermitRootLogin yes
```

改成这样：

```
PasswordAuthentication no
PermitRootLogin no
```

接下来，通过修改 `AddressFamily` 选项将 SSH 服务限制为 IPv4 或 IPv6。要将其更改为仅使用 IPv4（对大多数人来说应该没问题），请进行以下更改：

```
AddressFamily inet
```

重新启动 SSH 服务以启用你的更改。请注意，在重新启动 SSH 服务之前，与服务器建立两个活动连接是一个好主意。有了这些额外的连接，你可以在重新启动 SSH 服务出错的情况下修复所有问题。

在 Ubuntu 上：

```
$ sudo service sshd restart
```

在 Fedora 或 CentOS 或任何使用 Systemd 的系统上：

```
$ sudo systemctl restart sshd
```

### 5、启用防火墙

现在，你需要安装防火墙、启用防火墙并对其进行配置，以仅允许你指定的网络流量通过。（Ubuntu 上的）[简单的防火墙](https://launchpad.net/ufw)（UFW）是一个易用的 iptables 界面，可大大简化防火墙的配置过程。

你可以通过以下方式安装 UFW：

```
$ sudo apt install ufw
```

默认情况下，UFW 拒绝所有传入连接，并允许所有传出连接。这意味着服务器上的任何应用程序都可以访问互联网，但是任何尝试访问服务器的内容都无法连接。

首先，确保你可以通过启用对 SSH、HTTP 和 HTTPS 的访问来登录：

```
$ sudo ufw allow ssh
$ sudo ufw allow http
$ sudo ufw allow https
```

然后启用 UFW：

```
$ sudo ufw enable
```

你可以通过以下方式查看允许和拒绝了哪些服务：

```
$ sudo ufw status
```

如果你想禁用 UFW，可以通过键入以下命令来禁用：

```
$ sudo ufw disable
```

你还可以（在 RHEL/CentOS 上）使用 [firewall-cmd](https://www.redhat.com/sysadmin/secure-linux-network-firewall-cmd)，它已经安装并集成到某些发行版中。

### 6、安装 Fail2ban

[Fail2ban](https://www.fail2ban.org/wiki/index.php/Main_Page) 是一种用于检查服务器日志以查找重复或自动攻击的应用程序。如果找到任何攻击，它会更改防火墙以永久地或在指定的时间内阻止攻击者的 IP 地址。

你可以通过键入以下命令来安装 Fail2ban：

```
$ sudo apt install fail2ban -y
```

然后复制随附的配置文件：

```
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
```

重启 Fail2ban：

```
$ sudo service fail2ban restart
```

这样就行了。该软件将不断检查日志文件以查找攻击。一段时间后，该应用程序将建立相当多的封禁的 IP 地址列表。你可以通过以下方法查询 SSH 服务的当前状态来查看此列表：

```
$ sudo fail2ban-client status ssh
```

### 7、移除无用的网络服务

几乎所有 Linux 服务器操作系统都启用了一些面向网络的服务。你可能希望保留其中大多数，然而，有一些你或许希望删除。你可以使用 `ss` 命令查看所有正在运行的网络服务：（LCTT 译注：应该是只保留少部分，而所有确认无关的、无用的服务都应该停用或删除。）

```
$ sudo ss -atpu
```

`ss` 的输出取决于你的操作系统。下面是一个示例，它显示 SSH（`sshd`）和 Ngnix（`nginx`）服务正在侦听网络并准备连接：

```
tcp LISTEN 0 128 *:http *:* users:(("nginx",pid=22563,fd=7))
tcp LISTEN 0 128 *:ssh *:* users:(("sshd",pid=685,fd=3))
```

删除未使用的服务的方式因你的操作系统及其使用的程序包管理器而异。

要在 Debian / Ubuntu 上删除未使用的服务：

```
$ sudo apt purge <service_name>
```

要在 Red Hat/CentOS 上删除未使用的服务：

```
$ sudo yum remove <service_name>
```

再次运行 `ss -atup` 以确认这些未使用的服务没有安装和运行。

### 总结

本教程介绍了加固 Linux 服务器所需的最起码的措施。你应该根据服务器的使用方式启用其他安全层。这些安全层可以包括诸如各个应用程序配置、入侵检测软件（IDS）以及启用访问控制（例如，双因素身份验证）之类的东西。

---

via: <https://opensource.com/article/19/10/linux-server-security>

作者：[Patrick H. Mullins](https://opensource.com/users/pmullins) 选题：[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/) 荣誉推出


处理 Linux 文件的 3 个技巧

Summary: Linux 提供了许多用于查找、计数和重命名文件的命令。这有一些有用的选择。

Linux 提供了许多用于查找、计数和重命名文件的命令。这有一些有用的选择。

# 处理 Linux 文件的 3 个技巧

>
> Linux 提供了许多用于查找、计数和重命名文件的命令。这有一些有用的选择。
>
>
>

<img src="content_image/album_201910_11_101136ei4sslezne7esyis.jpg" alt="" title="">

Linux 提供了多种用于处理文件的命令，这些命令可以节省你的时间，并使你的工作不那么繁琐。

### 查找文件

当你查找文件时，`find` 可能会是第一个想到的命令，但是有时精心设计的 `ls` 命令会更好。想知道你昨天离开办公室回家前调用的脚本么？简单！使用 `ls` 命令并加上 `-ltr` 选项。最后一个列出的将是最近创建或更新的文件。

```
$ ls -ltr ~/bin | tail -3
-rwx------ 1 shs shs   229 Sep 22 19:37 checkCPU
-rwx------ 1 shs shs   285 Sep 22 19:37 ff
-rwxrw-r-- 1 shs shs  1629 Sep 22 19:37 test2
```

像这样的命令将仅列出今天更新的文件：

```
$ ls -al --time-style=+%D | grep `date +%D`
drwxr-xr-x  60 shs  shs       69632 09/23/19 .
drwxrwxr-x   2 shs  shs     8052736 09/23/19 bin
-rw-rw-r--   1 shs  shs         506 09/23/19 stats
```

如果你要查找的文件可能不在当前目录中，那么 `find` 将比 `ls` 提供更好的选项，但它可能会输出比你想要的更多结果。在下面的命令中，我们*不*搜索以点开头的目录（它们很多一直在更新），指定我们要查找的是文件（即不是目录），并要求仅显示最近一天 （`-mtime -1`）更新过的文件。

```
$ find . -not -path '*/\.*' -type f -mtime -1 -ls
   917517      0 -rwxrw-r--   1 shs      shs          683 Sep 23 11:00 ./newscript
```

注意 `-not` 选项反转了 `-path` 的行为，因此我们不会搜索以点开头的子目录。

如果只想查找最大的文件和目录，那么可以使用类似 `du` 这样的命令，它会按大小列出当前目录的内容。将输出通过管道传输到 `tail`，仅查看最大的几个。

```
$ du -kx | egrep -v "\./.+/" | sort -n | tail -5
918984      ./reports
1053980     ./notes
1217932     ./.cache
31470204    ./photos
39771212    .
```

`-k` 选项让 `du` 以块列出文件大小，而 `x` 可防止其遍历其他文件系统上的目录（例如，通过符号链接引用）。事实上，`du` 会先列出文件大小，这样可以按照大小排序（`sort -n`）。

### 文件计数

使用 `find` 命令可以很容易地计数任何特定目录中的文件。你只需要记住，`find` 会递归到子目录中，并将这些子目录中的文件与当前目录中的文件一起计数。在此命令中，我们计数一个特定用户（`username`）的家目录中的文件。根据家目录的权限，这可能需要使用 `sudo`。请记住，第一个参数是搜索的起点。这里指定的是用户的家目录。

```
$ find ~username -type f 2>/dev/null | wc -l
35624
```

请注意，我们正在将上面 `find` 命令的错误输出发送到 `/dev/null`，以避免搜索类似 `~username/.cache` 这类无法搜索并且对它的内容也不感兴趣的文件夹。

必要时，你可以使用 `maxdepth 1` 选项将 `find` 限制在单个目录中：

```
$ find /home/shs -maxdepth 1 -type f | wc -l
387
```

### 重命名文件

使用 `mv` 命令可以很容易地重命名文件，但是有时你会想重命名大量文件，并且不想花费大量时间。例如，要将你在当前目录的文件名中找到的所有空格更改为下划线，你可以使用如下命令：

```
$ rename 's/ /_/g' *
```

如你怀疑的那样，此命令中的 `g` 表示“全局”。这意味着该命令会将文件名中的*所有*空格更改为下划线，而不仅仅是第一个。

要从文本文件中删除 .txt 扩展名，可以使用如下命令：

```
$ rename 's/.txt//g' *
```

### 总结

Linux 命令行提供了许多用于处理文件的有用选择。请提出你认为特别有用的其他命令。

---

via: <https://www.networkworld.com/article/3440035/3-quick-tips-for-working-with-linux-files.html>

作者：[Sandra Henry-Stocker](https://www.networkworld.com/author/Sandra-Henry_Stocker/) 选题：[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/) 荣誉推出


如何用 GVM 管理 Go 项目

Summary: 使用 Go 版本管理器管理多个版本的 Go 语言环境及其模块。

使用 Go 版本管理器管理多个版本的 Go 语言环境及其模块。

# 如何用 GVM 管理 Go 项目

>
> 使用 Go 版本管理器管理多个版本的 Go 语言环境及其模块。
>
>
>

<img src="content_image/album_201910_11_112215m48u4zocc7p48okn.png" alt="" title="">

Go 语言版本管理器（[GVM](https://github.com/moovweb/gvm)）是管理 Go 语言环境的开源工具。GVM “pkgsets” 支持安装多个版本的 Go 并管理每个项目的模块。它最初由 [Josh Bussdieker](https://github.com/jbussdieker) 开发，GVM（像它的对手 Ruby RVM 一样）允许你为每个项目或一组项目创建一个开发环境，分离不同的 Go 版本和包依赖关系，以提供更大的灵活性，防止不同版本造成的问题。

有几种管理 Go 包的方式，包括内置于 Go 中的 Go 1.11 的 Modules。我发现 GVM 简单直观，即使我不用它来管理包，我还是会用它来管理 Go 不同的版本的。

### 安装 GVM

安装 GVM 很简单。[GVM 存储库](https://github.com/moovweb/gvm#installing)安装文档指示你下载安装程序脚本并将其传送到 Bash 来安装:

```
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
```

尽管越来越多的人采用这种安装方法，但是在安装之前先看看安装程序在做什么仍然是一个很好的想法。以 GVM 为例，该安装程序脚本:

1. 检查一些相关依赖性
2. 克隆 GVM 存储库
3. 使用 shell 脚本：
	* 安装 Go 语言
	* 管理 `GOPATH` 环境变量
	* 向 `bashrc`、`zshrc` 或配置文件中添加一行内容

如果你想确认它在做什么，你可以克隆该存储库并查看 shell 脚本，然后运行 `./binscripts/gvm-installer` 这个本地脚本进行设置。

`注意：` 因为 GVM 可以用来下载和编译新的 Go 版本，所以有一些预期的依赖关系，如 Make、Git 和 Curl。你可以在 [GVM 的自述文件](https://github.com/moovweb/gvm/blob/master/README.md)中找到完整的发行版列表。

### 使用 GVM 安装和管理 GO 版本

一旦安装了 GVM，你就可以使用它来安装和管理不同版本的 Go。`gvm listall` 命令显示可下载和编译的可用版本的 Go：

```
[chris@marvin ]$ gvm listall

gvm gos (available)

   go1
   go1.0.1
   go1.0.2
   go1.0.3

<输出截断>
```

安装特定的 Go 版本就像 `gvm install <版本>` 一样简单，其中 `<版本>` 是 `gvm listall` 命令返回的版本之一。

假设你正在进行一个使用 Go1.12.8 版本的项目。你可以使用 `gvm install go1.12.8` 安装这个版本:

```
[chris@marvin]$ gvm install go1.12.8
Installing go1.12.8...
 * Compiling...
go1.12.8 successfully installed!
```

输入 `gvm list`，你会看到 Go 版本 1.12.8 与系统 Go 版本（使用操作系统的软件包管理器打包的版本）一起并存：

```
[chris@marvin]$ gvm list

gvm gos (installed)

   go1.12.8
=> system
```

GVM 仍在使用系统版本的 Go ，由 `=>` 符号表示。你可以使用 `gvm use` 命令切换你的环境以使用新安装的 go1.12.8：

```
[chris@marvin]$ gvm use go1.12.8
Now using version go1.12.8

[chris@marvin]$ go version
go version go1.12.8 linux/amd64
```

GVM 使管理已安装版本的 Go 变得极其简单，但它不止于此！

### 使用 GVM pkgset

开箱即用，Go 有一种出色而令人沮丧的管理包和模块的方式。默认情况下，如果你 `go get` 获取一个包，它将被下载到 `$GOPATH` 目录中的 `src` 和 `pkg` 目录下，然后可以使用 `import` 将其包含在你的 Go 程序中。这使得获得软件包变得很容易，特别是对于非特权用户，而不需要 `sudo` 或 root 特权（很像 Python 中的 `pip install --user`）。然而，在不同的项目中管理相同包的不同版本是非常困难的。

有许多方法可以尝试修复或缓解这个问题，包括实验性 Go Modules（Go 1.11 版中增加了初步支持）和 [Go dep](https://golang.github.io/dep/)（Go Modules 的“官方实验”并且持续迭代）。在我发现 GVM 之前，我会在一个 Go 项目自己的 Docker 容器中构建和测试它，以确保分离。

GVM 通过使用 “pkgsets” 将项目的新目录附加到安装的 Go 版本的默认 `$GOPATH` 上，很好地实现了项目之间包的管理和隔离，就像 `$PATH` 在 Unix/Linux 系统上工作一样。

想象它如何运行的。首先，安装新版 Go 1.12.9：

```
[chris@marvin]$ echo $GOPATH
/home/chris/.gvm/pkgsets/go1.12.8/global

[chris@marvin]$ gvm install go1.12.9
Installing go1.12.9...
 * Compiling...
go1.12.9 successfully installed

[chris@marvin]$ gvm use go1.12.9
Now using version go1.12.9
```

当 GVM 被告知使用新版本时，它会更改为新的 `$GOPATH`，默认 `gloabl` pkgset 应用于该版本:

```
[chris@marvin]$ echo $GOPATH
/home/chris/.gvm/pkgsets/go1.12.9/global

[chris@marvin]$ gvm pkgset list

gvm go package sets (go1.12.9)

=>  global
```

尽管默认情况下没有安装额外的包，但是全局 pkgset 中的包对于使用该特定版本的 Go 的任何项目都是可用的。

现在，假设你正在启用一个新项目，它需要一个特定的包。首先，使用 GVM 创建一个新的 pkgset，名为 `introToGvm`:

```
[chris@marvin]$ gvm pkgset create introToGvm

[chris@marvin]$ gvm pkgset use introToGvm
Now using version go1.12.9@introToGvm

[chris@marvin]$ gvm pkgset list

gvm go package sets (go1.12.9)

    global
=>  introToGvm
```

如上所述，pkgset 的一个新目录被添加到 `$GOPATH`：

```
[chris@marvin]$ echo $GOPATH
/home/chris/.gvm/pkgsets/go1.12.9/introToGvm:/home/chris/.gvm/pkgsets/go1.12.9/global
```

将目录更改为预先设置的 `introToGvm` 路径，检查目录结构，这里使用 `awk` 和 `bash` 完成。

```
[chris@marvin]$ cd $( awk -F':' '{print $1}' <<< $GOPATH )
[chris@marvin]$ pwd
/home/chris/.gvm/pkgsets/go1.12.9/introToGvm

[chris@marvin]$ ls
overlay  pkg  src
```

请注意，新目录看起来很像普通的 `$GOPATH`。新的 Go 包使用同样的 `go get` 命令下载并正常使用，且添加到 pkgset 中。

例如，使用以下命令获取 `gorilla/mux` 包，然后检查 pkgset 的目录结构：

```
[chris@marvin]$ go get github.com/gorilla/mux
[chris@marvin]$ tree
[chris@marvin introToGvm ]$ tree
.
├── overlay
│   ├── bin
│   └── lib
│       └── pkgconfig
├── pkg
│   └── linux_amd64
│       └── github.com
│           └── gorilla
│               └── mux.a
src/
└── github.com
    └── gorilla
        └── mux
            ├── AUTHORS
            ├── bench_test.go
            ├── context.go
            ├── context_test.go
            ├── doc.go
            ├── example_authentication_middleware_test.go
            ├── example_cors_method_middleware_test.go
            ├── example_route_test.go
            ├── go.mod
            ├── LICENSE
            ├── middleware.go
            ├── middleware_test.go
            ├── mux.go
            ├── mux_test.go
            ├── old_test.go
            ├── README.md
            ├── regexp.go
            ├── route.go
            └── test_helpers.go
```

如你所见，`gorilla/mux` 已按预期添加到 pkgset `$GOPATH` 目录中，现在可用于使用此 pkgset 项目了。

### GVM 让 Go 管理变得轻而易举

GVM 是一种直观且非侵入性的管理 Go 版本和包的方式。它可以单独使用，也可以与其他 Go 模块管理技术结合使用并利用 GVM Go 版本管理功能。按 Go 版本和包依赖来分离项目使得开发更加容易，并且减少了管理版本冲突的复杂性，GVM 让这变得轻而易举。

---

via: <https://opensource.com/article/19/10/introduction-gvm>

作者：[Chris Collins](https://opensource.com/users/clcollins) 选题：[lujun9972](https://github.com/lujun9972) 译者：[heguangzhi](https://github.com/heguangzhi) 校对：[wxy](https://github.com/wxy)

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


Bash 学习的快乐之旅：3 个命令行游戏

Summary: 通过这些命令行游戏，学习有用的 Bash 技能也是一件乐事。

通过这些命令行游戏，学习有用的 Bash 技能也是一件乐事。

# Bash 学习的快乐之旅：3 个命令行游戏

>
> 通过这些命令行游戏，学习有用的 Bash 技能也是一件乐事。
>
>
>

学习是件艰苦的工作，然而没有人喜欢工作。这意味着无论学习 Bash 多么容易，它仍然对你来说就像工作一样。当然，除非你通过游戏来学习。

你不会觉得会有很多游戏可以教你如何使用 Bash 终端吧，这是对的。严肃的 PC 游戏玩家知道，《<ruby> 辐射 <rt>  Fallout </rt></ruby>》系列在金库中配备了基于终端的计算机，这可以帮你理解通过文本与计算机进行交互是什么样子，但是尽管其功能或多或少地类似于 [Alpine](https://opensource.com/article/17/10/alpine-email-client) 或 [Emacs](http://www.gnu.org/software/emacs)，可是玩《辐射》并不会教给你可以在现实生活中使用的命令或应用程序。《辐射》系列从未直接移植到Linux（尽管可以通过 Steam 的开源的 [Proton](https://github.com/ValveSoftware/Proton/) 来玩。）曾是《辐射》的前身的《<ruby>   废土  <rt>  Wasteland </rt></ruby>》系列的最新作品倒是面向 Linux 的，因此，如果你想体验游戏中的终端，可以在你的 Linux 游戏计算机上玩《[废土 2](https://www.inxile-entertainment.com/wasteland2)》和《[废土 3](https://www.inxile-entertainment.com/wasteland3)》。《<ruby>   暗影狂奔  <rt>  Shadowrun </rt></ruby>》系列也有面向 Linux 的版本，它有许多基于终端的交互，尽管公认 [hot sim](https://forums.shadowruntabletop.com/index.php?topic=21804.0) 序列常常使它黯然失色。

虽然这些游戏中采用了有趣的操作计算机终端的方式，并且可以在开源的系统上运行，但它们本身都不是开源的。不过，至少有两个游戏采用了严肃且非常有趣的方法来教人们如何通过文本命令与系统进行交互。最重要的是，它们是开源的。

### Bashcrawl

你可能听说过《<ruby>   巨洞探险  <rt>  Colossal Cave Adventure </rt></ruby>》游戏，这是一款古老的基于文本的交互式游戏，其风格为“自由冒险”类。早期的计算机爱好者们在 DOS 或 ProDOS 命令行上痴迷地玩这些游戏，他们努力寻找有效语法和（如一个讽刺黑客所解释的）滑稽幻想逻辑的正确组合来击败游戏。想象一下，如果除了探索虚拟的中世纪地下城之外，挑战还在于回忆起有效的 Bash 命令，那么这样的挑战会多么有成效。这就是 [Bashcrawl](https://gitlab.com/slackermedia/bashcrawl) 的基调，这是一个基于 Bash 的地下城探险游戏，你可以通过学习和使用 Bash 命令来玩这个游戏。

在 Bashcrawl 中，“地下城”是以目录和文件的形式创建在你的计算机上的。你可以通过使用 `cd` 命令更改目录进入地下城的每个房间来探索它。当你[穿行目录](https://opensource.com/article/19/8/understanding-file-paths-linux)时，你可以用 [ls -F](https://opensource.com/article/19/7/master-ls-command) 来查看文件，用 [cat](https://opensource.com/article/19/2/getting-started-cat-command) 读取文件，[设置变量](https://opensource.com/article/19/8/using-variables-bash)来收集宝藏，并运行脚本来与怪物战斗。你在游戏中所做的一切操作都是有效的 Bash 命令，你可以稍后在现实生活中使用它，玩这个游戏提供了 Bash 体验，因为这个“游戏”是由计算机上的实际目录和文件组成的。

```
$ cd entrance/
$ ls
cellar  scroll
$ cat scroll

It is pitch black in these catacombs.
You have a magical spell that lists all items in a room.

To see in the dark, type:     ls
To move around, type:         cd <directory>

Try looking around this room.
Then move into one of the next rooms.

EXAMPLE:

$ ls
$ cd cellar

Remember to cast ``ls`` when you get into the next room!
$
```

#### 安装 Bashcrawl

在玩 Bashcrawl 之前，你的系统上必须有 Bash 或 [Zsh](https://opensource.com/article/19/9/getting-started-zsh)。Linux、BSD 和 MacOS 都附带了 Bash。Windows 用户可以下载并安装 [Cygwin](https://www.cygwin.com/) 或 [WSL](https://docs.microsoft.com/en-us/windows/wsl/wsl2-about) 或[试试 Linux](https://opensource.com/article/19/7/ways-get-started-linux)。

要安装 Bashcrawl，请在 Firefox 或你选择的 Web 浏览器中导航到这个 [GitLab 存储库](https://gitlab.com/slackermedia/bashcrawl)。在页面的右侧，单击“下载”图标（位于“Find file”按钮右侧）。在“下载”弹出菜单中，单击“zip”按钮以下载最新版本的游戏。

下载完成后，解压缩该存档文件。

另外，如果你想从终端中开始安装，则可以使用 [Git](https://opensource.com/life/16/7/stumbling-git) 命令：

```
$ git clone https://gitlab.com/slackermedia/bashcrawl.git bashcrawl
```

#### 游戏入门

与你下载的几乎所有新的软件包一样，你必须做的第一件事是阅读 README 文件。你可以通过双击`bashcrawl` 目录中的 `README.md` 文件来阅读。在 Mac 上，你的计算机可能不知道要使用哪个应用程序打开该文件；你也可以使用任何文本编辑器或 LibreOffice 打开它。`README.md` 这个文件会具体告诉你如何开始玩游戏，包括如何在终端上进入游戏以及要开始游戏必须发出的第一条命令。如果你无法阅读 README 文件，那游戏就不战自胜了（尽管由于你没有玩而无法告诉你）。

Bashcrawl 并不意味着是给比较聪明或高级用户玩的。相反，为了对新用户透明，它尽可能地简单。理想情况下，新的 Bash 用户可以从游戏中学习 Bash 的一些基础知识，然后会偶然发现一些游戏机制，包括使游戏运行起来的简单脚本，并学习到更多的 Bash 知识。此外，新的 Bash 用户可以按照 Bashcrawl 现有内容的示例设计自己的地下城，没有比编写游戏更好的学习编码的方法了。

### 命令行英雄：BASH

Bashcrawl 适用于绝对初学者。如果你经常使用 Bash，则很有可能会尝试通过以初学者尚不了解的方式查看 Bashcrawl 的文件，从而找到胜过它的秘径。如果你是中高级的 Bash 用户，则应尝试一下 [命令行英雄：BASH](https://www.redhat.com/en/command-line-heroes/bash/index.html?extIdCarryOver=true&sc_cid=701f2000001OH79AAG)。

这个游戏很简单：在给定的时间内输入尽可能多的有效命令（LCTT 译注：BASH 也有“猛击”的意思）。听起来很简单。作为 Bash 用户，你每天都会使用许多命令。对于 Linux 用户来说，你知道在哪里可以找到命令列表。仅 util-linux 软件包就包含一百多个命令！问题是，在倒计时的压力下，你的指尖是否忙的过来输入这些命令？

这个游戏听起来很简单，它确实也很简单！原则上，它与<ruby> 闪卡 <rt>  flashcard </rt></ruby>相似，只是反过来而已。在实践中，这是测试你的知识和回忆的一种有趣方式。当然，它是开源的，是由 [Open Jam](http://openjam.io/) 的开发者开发的。

#### 安装

你可以[在线](https://www.redhat.com/en/command-line-heroes/bash/index.html)玩“命令行英雄：BASH”，或者你也可以从 [GitHub](https://github.com/CommandLineHeroes/clh-bash/) 下载它的源代码。

这个游戏是用 Node.js 编写的，因此除非你想帮助开发该游戏，否则在线进行游戏就够了。

### 在 Bash 中扫雷

如果你是高级 Bash 用户，并且已经编写了多个 Bash 脚本，那么你可能不仅仅想学习 Bash。你可以尝试编写游戏而不是玩游戏，这才是真的挑战。稍加思考，用上一个下午或几个小时，便可以在 Bash 中实现流行的游戏《扫雷》。你可以先尝试自己编写这个游戏，然后参阅 Abhishek Tamrakar 的[文章](/article-11430-1.html)，以了解他如何完成该游戏的。

有时编程没有什么目的而是为了教育。在 Bash 中编写的游戏可能不是可以让你在网上赢得声誉的项目，但是该过程可能会很有趣且很有启发性。面对一个你从未想到的问题，这是学习新技巧的好方法。

### 学习 Bash，玩得开心

不管你如何学习它，Bash 都是一个功能强大的界面，因为它使你能够指示计算机执行所需的操作，而无需通过图形界面的应用程序的“中间人”界面。有时，图形界面很有帮助，但有时你想离开那些已经非常了解的东西，然后转向可以快速或通过自动化来完成的事情。由于 Bash 基于文本，因此易于编写脚本，使其成为自动化作业的理想起点。

了解 Bash 以开始走向高级用户之路，但是请确保你乐在其中。

---

via: <https://opensource.com/article/19/10/learn-bash-command-line-games>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[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/) 荣誉推出


如何在 CentOS 8/RHEL 8 上安装和使用 Cockpit

ss -tunlp | grep cockpit

无返回

ps auxf|grep cockpit

返回

root        2679  0.0  0.0 221900  1088 pts/1    S+   17:09   0:00  |           \_ grep --color=auto cockpit

# 如何在 CentOS 8/RHEL 8 上安装和使用 Cockpit

Cockpit 是一个基于 Web 的服务器管理工具，可用于 CentOS 和 RHEL 系统。最近发布的 CentOS 8 和 RHEL 8，其中 cockpit 是默认的服务器管理工具。它的软件包在默认的 CentOS 8 和 RHEL 8 仓库中就有。Cockpit 是一个有用的基于 Web 的 GUI 工具，系统管理员可以通过该工具监控和管理 Linux 服务器，它还可用于管理服务器、容器、虚拟机中的网络和存储，以及检查系统和应用的日志。

在本文中，我们将演示如何在 CentOS 8 和 RHEL 8 中安装和设置 Cockpit。

### 在 CentOS 8/RHEL 8 上安装和设置Cockpit

登录你的 CentOS 8/RHEL 8，打开终端并执行以下 `dnf` 命令：

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

运行以下命令启用并启动 cockpit 服务：

```
[root@linuxtechi ~]# systemctl start cockpit.socket
[root@linuxtechi ~]# systemctl enable cockpit.socket
```

使用以下命令在系统防火墙中允许 Cockpit 端口：

```
[root@linuxtechi ~]# firewall-cmd --permanent --add-service=cockpit
[root@linuxtechi ~]# firewall-cmd --reload
```

验证 cockpit 服务是否已启动和运行，执行以下命令：

```
[root@linuxtechi ~]# systemctl status cockpit.socket
[root@linuxtechi ~]# ss -tunlp | grep cockpit
[root@linuxtechi ~]# ps auxf|grep cockpit
```

### 在 CentOS 8/RHEL 8 上访问 Cockpit

正如我们在上面命令的输出中看到的，cockpit 正在监听 tcp 9090 端口，打开你的 Web 浏览器并输入 url：`https://<Your-CentOS8/RHEL8-System-IP>:9090`。

RHEL 8 中的 Cockpit 登录页面：

使用有管理员权限的用户名，或者我们也可以使用 root 用户的密码登录。如果要将管理员权限分配给任何本地用户，请执行以下命令：

```
[root@linuxtechi ~]# usermod -G wheel pkumar
```

这里 `pkumar` 是我的本地用户，

在输入用户密码后，选择 “Reuse my password for privileged tasks”，然后单击 “Log In”，然后我们看到以下页面：

在左侧栏上，我们可以看到可以通过 cockpit GUI 监控和配置的内容，

假设你要检查 CentOS 8/RHEL 8 中是否有任何可用更新，请单击 “System Updates”：

要安装所有更新，点击 “Install All Updates”：

如果想要修改网络并要添加 Bond 接口和网桥，请单击 “Networking”：

如上所见，我们有创建 Bond 接口、网桥和 VLAN 标记接口的选项。

假设我们想创建一个 `br0` 网桥，并要为它添加 `enp0s3` 端口，单击 “Add Bridge”：

将网桥名称指定为 `br0`，将端口指定为 `enp0s3`，然后单击“Apply”。

在下个页面，我们将看到该网桥处于活动状态，并且获得了与 enp0s3 接口相同的 IP：

如果你想检查系统日志，单击 “Logs”，我们可以根据严重性查看日志：

本文就是这些了，类似地，系统管理员可以使用 cockpit 的其他功能来监控和管理 CentOS 8 和 RHEL 8 服务器。如果这些步骤可以帮助你在 Linux 服务器上设置 cockpit，请在下面的评论栏分享你的反馈和意见。

---

via: <https://www.linuxtechi.com/install-use-cockpit-tool-centos8-rhel8/>

作者：[Pradeep Kumar](https://www.linuxtechi.com/author/pradeep/) 选题：[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/) 荣誉推出