> For the complete documentation index, see [llms.txt](https://s-klnw.gitbook.io/study-manual/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://s-klnw.gitbook.io/study-manual/0.-linux-commands/1.1-xi-tong-guan-li-lei-ming-ling.md).

# 1.1 系统管理类命令

计算机发明早期体量非常巨大，动辄按吨计算，只能放在专门的机房里。因此，用户使用一种叫「终端」（Terminal Emulator）的外部设备操作计算机。终端只负责输入和显示，不参与计算。后来，随着个人计算机的兴起，用户不再需要额外的终端设备操作计算机。同时，终端的概念在操作系统里保留了下来，变成终端模拟器软件。

现在，大部分用户都通过图形化 shell 界面与计算机交互，比如 [macOS](/study-manual/0.-linux-commands/3.-mac-terminal.md)。更多 shell 介绍和使用，参见 [1.3 shell 脚本编程](/study-manual/0.-linux-commands/1.3-bash-introduce.md#unix-shell)。

本节的终端基础命令介绍将以 CentOS Linux 8 为例。

<div align="left"><figure><img src="/files/WPuKK78QE00e7VjbWmtq" alt="" width="150"><figcaption><p>Tux，Linux 的吉祥物</p></figcaption></figure></div>

## 主机名称

在大多数 Linux 发行版中，都使用 `hostname` 命令查看或更改主机名。主机名用于标识网络中的计算机。<mark style="color:$danger;">修改主机名的操作需要重新登录后才能生效。</mark>修改主机名称方法如下：

```bash
[zhangzh@node01 ~]$ su
[root@node01 ~]# hostnamectl
   Static hostname: node01
         Icon name: computer-server
           Chassis: server
        Machine ID: 6c1247f5013f4ea08698f184fd35efb8
           Boot ID: 831d4163ee26402e88b8325ef19b406c
  Operating System: CentOS Linux 8
       CPE OS Name: cpe:/o:centos:centos:8
            Kernel: Linux 4.18.0-240.el8.x86_64
      Architecture: x86-64
[root@node01 ~]# hostnamectl set-hostname 新主机名
[root@node01 ~]# exit
logout
[zhangzh@node01 ~]$ 
```

{% hint style="info" %}
在 Linux 系统中，用户主要分为两大类：普通用户和超级用户/管理员，后者通常特指 root 用户。root 对系统拥有绝对权力；而普通用户只对个人目录<sup>\[1]</sup>下的文件拥有完全控制权。

<mark style="color:$danger;">直接以管理员身份操作 shell 是危险的，所以计算机用户通常以普通用户登录。</mark>

示例代码中 `[zhangzh@node01 ~]$` 分别表示以用户名为 `zhangzh` 的用户登录主机名为 `node01` 的主机。

**su命令**（switch uesr）用于变更使用者身份。常见用法如：`su username` 或者 `su -c command username`，其含义分别是切换至用户名为 `username` 的账户和切换至 `username` 的账户后执行命令后退出该账户。直接输入 `su` 命令可以从普通用户切换到 `root shell` 中，输入 `exit` 可以退出 `root shell`。

当 `root` 用户登录时 `$` 符号会变为 `#` 符号，以示区分。

* <mark style="color:$info;">\[1] 在 Linux 里一切皆文件。普通文件存放数据，目录文件（folder）存放「文件名 → inode 的映射表」，所以目录本身也是一种（特殊的）文件，或者叫做「文件夹」。</mark>
  {% endhint %}

{% hint style="info" %}
Linux 命令的完整执行语法通常由 `命令 选项 参数` 构成，如 `hostnamectl set-hostname 新主机名`。选项是可选的，用来改变命令行为。不使用参数时，命令会使用默认配置，参数也是可选的，一般是命令要操作的对象。
{% endhint %}

## 电源管理

服务器和电脑都是计算机的一种形式，都可以开关机和重启。

**重启命令** e.g.

```bash
[zhangzh@node01 ~]$ bash          # 仅适用于账户的重启
[zhangzh@node01 ~]# reboot now    # 适用于对服务器的重启
```

**关闭命令** e.g.

```bash
[zhangzh@node01 ~]# shutdown now    # 立刻关机
[zhangzh@node01 ~]# shutdown 20:30  # 今晚八点半关机
[zhangzh@node01 ~]# shutdown +20    # 20min后关机
```

## 密码设置

**passwd命令** 设置用户的认证信息，包括用户密码、密码过期时间等。只有 root 用户可以指定用户名称或者修改其他用户的密码，普通用户只能修改个人密码。

修改其他用户的密码方式参考本章[#yong-hu-guan-li](#yong-hu-guan-li "mention")一节；找回 root 密码的方法参考[这篇博文](http://t.zoukankan.com/canyezhizi-p-13574958.html)。

## 远程控制

在高能物理计算中，数据处理和模拟通常在远程的高性能计算集群或服务器上进行。因此，需要一个“安全的桥梁”来连接本地终端与远程服务器。

**ssh命令**（Secure Shell） 远程连接服务器。

**交互式登录模式**，创建一个交互式 shell 会话，也就是常说的「登录」。e.g.

```bash
[zhangzh@node01 ~]$ ssh -p 8022 zhangzh@222.2.2.102
```

{% hint style="info" %}
`-p` 选项表示指定端口号；`8022` 是指定的[端口](#di-zhi-yu-duan-kou)（不指定端口默端口号为 `22`）；`zhangzh` 是登录账户名；`@` 后面是访问[地址](#di-zhi-yu-duan-kou) `222.2.2.102`。
{% endhint %}

【注】开启 GUI 转发服务时，需要额外添加 `-XY` 选项。在 macOS 中可以[1.5 macOS Ventura](/study-manual/0.-linux-commands/3.-mac-terminal.md#shi-yong-xquartz-diao-yong-gui-jie-mian)。

**非交互式命令执行模式**，执行单个指定命令后立即退出，不进入交互式 shell。e.g.

```shellscript
[root@node01 ~]# ssh node02 "free -h"
              total        used        free      shared  buff/cache   available
Mem:          251Gi       4.5Gi        28Gi       714Mi       217Gi       244Gi
Swap:          29Gi       1.2Gi        28Gi
[root@node01 ~]# ssh node02 "date; whoami; pwd"              # 用分号分隔多个命令
[root@node01 ~]# ssh node02 "bash /path/to/remote_script.sh" # 执行脚本
[zhangzh@node01 ~]$ ssh node02 "free -h"                     # 没有配置免密登录时需要输入密码
zhangzh@node02's password:
[zhangzh@node01 ~]$ ssh root@node02 "free -h"
root@node02's password: 
```

#### 免密登录

每次登录都输入密码未免太过麻烦，因此，可以在值得信任的计算机上执行 `ssh-keygen` 命令，生成 ssh 钥匙。macOS 中钥匙的路径存放在 `.ssh/`。e.g.

```bash
local$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Created directory '/home/user/.ssh'.
Enter passphrase (empty for no passphrase):    <====空格
Enter same passphrase again:                   
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:47VkvSjlFhKRgz/6RYdXM2EULtk9TQ65PDWJjYC5Jys user@local
The key's randomart image is:
+---[RSA 2048]----+
|       ...o...X+o|
|      . o+   B=Oo|
|       .....ooo*=|
|        o+ooo.+ .|
|       .SoXo.  . |
|      .E X.+ .   |
|       .+.= .    |
|        .o       |
|                 |
+----[SHA256]-----+
```

接下来将公钥内容拷贝至需要控制的服务器即可实现免密登录。e.g.

```bash
local$ ssh zhangzh@222.19.64.20 -p 8022 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
```

#### **配置登录服务器**

为服务器配置别名。e.g. 命名 `zhangzh@222.19.64.20` 为 `klcr`， 在 `.ssh/config` 中写入：

```bash
Host klcr
	Hostname 222.19.64.20
	Port 8022
	User zhangzh
	IdentityFile ~/.ssh/id_rsa
```

至此，就完成了服务器的别名配置，输入 `ssh klcr` 即可免密访问服务器。

在终端中上传和下载本地或服务器文件的方法参见[1.2 文件管理类命令](/study-manual/0.-linux-commands/1.2-wen-jian-guan-li-lei-ming-ling.md#kua-fu-wu-qi-chuan-wen-jian)章节内容。

## 服务管理

通过命令控制系统服务（如网络、下载器等）的启动、停止、重启以及开机自启状态。

#### **启动服务**

不同系统的服务启动指令略有差异，本系统使用 `systemctl start` 启动。e.g.

```shell
[zhangzh@node01 ~]$ systemctl start yum
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
Authentication is required to start 'yum.service'.
Authenticating as: root
```

#### 暂停服务

**标准的暂停：**

```shellscript
[zhangzh@node01 ~]$ systemctl stop 服务名
```

**永久禁用：**

```shellscript
[zhangzh@node01 ~]$ systemctl disable 服务名
```

#### 允许开机自启

将服务加入开机启动项。配置成功后，每次服务器重启，该服务都会在后台自动拉起。e.g.

```
[zhangzh@node01 ~]$ systemctl enable nginx
```

【注】该命令本质上是在系统的 `/etc/systemd/system/` 目录下创建了一个指向服务脚本的软链接。

#### 取消开机自启 (Disable)

移除开机启动项。服务器下次重启时，该服务默认不会自动运行，但依然可以在系统启动后手动通过 `systemctl start` 把它唤醒。e.g.

```
[zhangzh@node01 ~]$ systemctl disable nginx
```

## 用户管理

用户管理涉及到<mark style="color:purple;">**组**</mark>与<mark style="color:purple;">**用户**</mark>以及权限的概念。通常，普通用户只对自己的文件具有完整权限，同组用户拥有相对完整的权限，对组外（其他）用户不具备任何权限。权限控制介绍参见[1.2 文件管理类命令](/study-manual/0.-linux-commands/1.2-wen-jian-guan-li-lei-ming-ling.md#quan-xian)。

* **useradd命令** 创建用户帐号。
* **usermod命令** 修改用户帐号。
* **userdel命令** 删除用户帐号。

**组管理命令：**

```shell
# groupadd groupname                 # 新建用户组
# groupadd -n groupname newgroupname # 修改用户组名称
# groupdel groupname                 # 删除用户组
```

**用户管理命令：**

```shell
# useradd username                   # 新建用户
# useradd -d /home/users username    # 指定根目录创建用户
# useradd -g groupname username      # 新建用户并指定用户组
# usermod -g groupname username      # 为新建用户指定用户组
# passwd username                    # 修改用户密码
# userdel -r username                # 删除用户及主目录
# whois username                     # 查询用户
```

{% hint style="danger" %}
当创建用户时出现 `Creating mailbox file: File exists` 的错误。请直接删除 `/var/spool/mail/` 和 `/home` 下的之前存在的用户文件，删除后就能重建成功。
{% endhint %}

<details>

<summary>e.g. 添加用户的简单流程</summary>

```sh
[root@node02 l]# useradd -d /home/users/l/lixl lixl
[root@node02 l]# ls
lixl
[root@node02 l]# passwd lixl
Changing password for user lixl.
New password: 
BAD PASSWORD: The password fails the dictionary check - it is too simplistic/systematic
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@node02 l]# usermod -g ybj lixl
[root@node02 l]# ll
total 4
drwx------ 3 lixl ybj 4096 Aug  1 13:40 lixl
[root@node02 l]#
```

</details>

## **进程管理**

每一个运行中的程序、脚本或后台守护都被称为一个**进程**（Process）。当服务器运行变慢、内存被占满，或者某个分析脚本卡死时，根据需要可以监控并管理这些进程。

**top命令** 查看进程及设备运行情况。界面支持个性化：按 `Z` 键更改界面颜色，按 `shift+Z`，依次点按 `S` 和数字 `0-7` 可以更改对应位置的字体颜色，按 `T` 和 `M` 可以切换显示 CPU、GPU 的占用显示，回车后按 `W` 键保存更改。

{% tabs %}
{% tab title="top 命令" %}

```bash
top - 21:05:17 up 10 days, 16:30,  6 users,  load average: 0.00, 0.00, 0.00
Tasks: 1162 total,   1 running, 1161 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem : 257284.2 total, 231838.1 free,   3752.3 used,  21693.8 buff/cache
MiB Swap:  30517.0 total,  30517.0 free,      0.0 used. 251483.6 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND              
     12 root      20   0       0      0      0 I   0.3   0.0  35:25.93 rcu_sched            
   2988 rngd      20   0  376296   8608   5492 S   0.3   0.0   4:53.00 rngd                 
2070853 zhangzh   20   0  276376   6572   4604 R   0.3   0.0   0:00.36 top                  
      1 root      20   0  243500  11876   8304 S   0.0   0.0   1:01.35 systemd              
      2 root      20   0       0      0      0 S   0.0   0.0   0:00.86 kthreadd             
      3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp               
      4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp           
      6 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/0:0H         
```

{% endtab %}

{% tab title="w 命令" %}

```bash
[zhangzh@node01 ~]$ w 
 14:09:47 up 1 day,  1:23,  5 users,  load average: 296.24, 296.26, 296.21
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
lixl     pts/1    222.19.66.192    10:35    1:48m  0.70s  0.62s vim shell_020.sh
lixl     pts/2    222.19.66.192    10:38    2:21m  0.10s  0.10s -bash
lixl     pts/3    222.19.66.192    13:28   33.00s  0.11s  0.03s vim shell_021
zhangzh  pts/4    172.29.85.47     13:44    3.00s  0.11s  0.04s wbash
```

{% endtab %}

{% tab title="美化后的 top 界面" %}

```bash
top - 19:18:49 up 6 days, 11:51,  6 users,  load average: 105.10, 104.52, 90.03
Tasks: 1329 total, 106 running, 1222 sleeping,   1 stopped,   0 zombie
%Cpu(s):  93.3/0.5    94[||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||     ]
MiB Mem :  6.9/257284.2 [|||||                                                                    ]
MiB Swap:  5.5/30517.0  [||||                                                                     ]
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                     
 137605 liulw     20   0  116184  48608   4556 R  99.7   0.0   8439:25 ./corsika74100Linux_QGSJET_+
 151409 liulw     20   0  116184  48628   4572 R  99.7   0.0   8437:22 ./corsika74100Linux_QGSJET_+
 400337 liulw     20   0  116184  44392   4440 R  99.7   0.0  21:43.59 ./corsika74100Linux_QGSJET_+
 410036 liulw     20   0  116184  44580   4624 R  99.7   0.0  21:43.37 ./corsika74100Linux_QGSJET_+
 449661 liulw     20   0  116184  27928   4468 R  99.7   0.0  21:42.83 ./corsika74100Linux_QGSJET_+
 502299 liulw     20   0  116184  27284   4052 R  99.7   0.0  21:41.53 ./corsika74100Linux_QGSJET_+
```

{% endtab %}
{% endtabs %}

**w命令** 显示登录用户列表、用户正在执行的进程、登录地点、登录时间等信息。还可用于查看系统时间，这一点和 `uptime` 作用一致。更多关于时间的命令可以参考[命令附录](/study-manual/0.-linux-commands/1.4-linux-ming-ling-fu-lu.md)。该命令参数如下：

```
 -f, --from          显示用户从哪登录；
 -i, --ip-addr       显示IP地址而不是主机名（如果可能）
     --help          显示此帮助并退出
```

<mark style="color:$success;">**jobs命令**</mark> <mark style="color:$success;">显示作业的状态，如列出活动和停止的作业。</mark>

`jobs` 常用参数是 `jobs -l`：以包含 `pid` 的形式展示进程。

【注】`jobs` 只能查看当前账户的进程。诸如 `nohup` 之类的命令，在重新登录后 `jobs` 则无法查询到该进程，这时候建议使用 `ps` 命令来管理。

<mark style="color:$success;">**ps命令**</mark><mark style="color:$success;">（process status）报告当前系统的进程状态。</mark>

搭配 `kill` 指令随时中断、删除不必要的程序。`ps` 是最基本和最强大的进程查看命令。如 `ps -aux` 配合 `grep` 命令查找需要的进程，并打印 ID 号和所属用户。

**pstree命令** 以一种优雅的方式展示进程树。

#### 当进程严重影响到服务器的运行时，管理员可以结束特定用户的特定进程。

**kill命令** 通过进程 ID（Process ID, PID）关闭进程。<mark style="color:$success;">使用</mark> <mark style="color:$success;">`kill -9`</mark> <mark style="color:$success;">命令立即杀死指定 PID 的进程。</mark>使用 `ps` 等命令配合 `grep` 来查找进程 ID。

**killall命令** 关闭指定用户名称的所有进程。

**pkill命令** 按照进程名杀死进程。`pkill` 和 `killall` 应用方法差不多，也是直接杀死运行中的程序；如果想杀掉单个进程，使用 `kill`。

```shellscript
# pkill -u username
# killall -u username
```

<mark style="color:$success;">**进程中无法输入 kill 时，使用如下命令中止或挂起进程。**</mark>

```shellscript
ctrl c     # 中断进程，如无法中断时
ctrl z     # 将进程调入后台，可以使用fg和bg命令前台或后台继续该任务
ctrl \     # 直接退出当前程序
```

{% hint style="danger" %}
当需要 `kill` 某项进程时，请先关闭该进程之前的进程，否则可能会报错。如 `nohup ping`，应先 `kill ping`，再 `kill nohup`。
{% endhint %}

## 配置文件

**环境变量**是用来存储有关 shell 会话和工作环境的信息的一种特性。

这项特性允许在内存中存储数据以便程序或 shell 中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。

{% hint style="warning" %}
变量名区分大小写。所有的环境变量名均使用大写字母，这是 bash shell 的标准惯例。

如果是个人创建的局部变量或是 shell 脚本，使用小写字母，这能够避免重新定义系统环境变量可能带来的灾难。
{% endhint %}

{% hint style="danger" %} <mark style="color:$danger;">变量名、等号和值之间没有空格，这一点非常重要。如果在赋值表达式中加上了空格，bash shell 就会把值当成一个单独的命令</mark>
{% endhint %}

根据作用域的不同，环境变量分为两种：<mark style="color:purple;">全局环境变量</mark>和<mark style="color:purple;">局部环境变量</mark>。使用 `echo` 显示变量的值。在这种情况下引用某个环境变量的时候，必须在变量前面加上一个美元符 `$`。e.g.

```bash
[zhangzh@node01 sshpass-1.08]$ echo $HOME
/home/users/z/zhangzh
```

在变量名前加上 `$` 可不仅仅是要显示变量当前的值。它能够让变量作为命令行参数。e.g.

```bash
[zhangzh@node01 sshpass-1.08]$ ls $HOME
asgamma  bin  grb  other  practice  software  wl
[zhangzh@node01 sshpass-1.08]$ ls /home/users/z/zhangzh/
asgamma  bin  grb  other  practice  software  wl
```

一旦启动了 bash shell（或者执行一个 shell 脚本），就能创建在这个 shell 进程内可见的局部变量了。可以通过 `=` 给环境变量赋值，值可以是数值或字符串，如果要给变量赋一个含有空格的字符串值，必须用引号来界定字符串的首和尾。e.g.

```bash
[zhangzh@node01 sshpass-1.08]$ echo $my_var          # 为定义的变量会返回空值                                                                                                                               
                                                                
[zhangzh@node01 sshpass-1.08]$ my_var=hello
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello
[zhangzh@node01 sshpass-1.08]$ my_var=hello world    # 没有单引号的话，bash shell会以为下一个词是另一个要执行的命令
bash: world: 未找到命令...
[zhangzh@node01 sshpass-1.08]$ my_var="hello world"
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello world
[zhangzh@node01 sshpass-1.08]$ my_var='hello linux'  # 单双引号不做区别
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello linux
```

设置了局部环境变量后，就能在 shell 进程的任何地方使用它了。但是，如果生成了另外一个 shell，它在子 shell 中就不可用。e.g.

```bash
[zhangzh@node01 sshpass-1.08]$ my_var='hello linux'
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello linux
[zhangzh@node01 sshpass-1.08]$ bash    # 新建bash会话
[zhangzh@node01 sshpass-1.08]$ echo $my_var

[zhangzh@node01 sshpass-1.08]$
```

在子 shell 中无法使用用户定义变量 `my_var`。通过命令 `echo $my_var` 所返回的空行就能够证明这一点。

当退出子 shell 并回到原来的 shell 时，这个局部环境变量依然可用，类似地，如果在子进程中设置了一个局部变量，那么一旦退出了子进程，那个局部环境变量就不可用。

<mark style="color:$danger;">**那么需要该变量在所有进程中都是可见的，就需要设置全局变量。**</mark>

#### **全局变量**

创建全局环境变量的方法是先创建一个局部环境变量，然后再把它导出到全局环境中，这个过程通过 `export` 命令来完成，**变量名前面不需要加** `$` 。

```bash
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello linux
[zhangzh@node01 sshpass-1.08]$ export my_var    # 变量名前面不需要加 $
[zhangzh@node01 sshpass-1.08]$ bash
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello linux
```

修改子 shell 中全局环境变量并不会影响到父 shell 中该变量的值，子 shell 甚至无法使用 `export` 命令改变父 shell 中全局环境变量的值，甚至子 shell 重新定义并导出了变量 `my_var`，但父 shell 中的 `my_var` 变量依然保留着原先的值。

当然，既然可以创建新的环境变量，自然也能删除已经存在的环境变量。可以用 `unset` 命令完成这个操作。在 `unset` 命令中引用环境变量时，**记住不要使用** `$`。

```bash
[zhangzh@node01 sshpass-1.08]$ echo $my_var
hello linux
[zhangzh@node01 sshpass-1.08]$ unset my_var
[zhangzh@node01 sshpass-1.08]$ echo $my_var

[zhangzh@node01 sshpass-1.08]$ 
```

{% hint style="success" %}
在涉及环境变量名时，什么时候该使用 `$`，什么时候不该使用 `$`，实在让人摸不着头脑。

记住一点就行了：如果要用到变量，使用 `$`；如果要操作变量，不使用 `$`。

这条规则的一个例外就是使用 `printenv` 显示某个变量的值。
{% endhint %}

<mark style="color:$danger;">**如果子进程中删除了一个全局环境变量， 这只对子进程有效。该全局环境变量在父进程中依然可用。**</mark>

默认的环境变量有很多，在[这里](https://blog.csdn.net/Michael177/article/details/124639138)查看全部的默认变量，这里列出一些常用的环境变量名称：

<table><thead><tr><th width="228.36328125">常用环境变量</th><th>作用</th></tr></thead><tbody><tr><td><strong>PATH</strong></td><td><strong>决定了 shell 将到哪些目录中寻找命令或程序</strong></td></tr><tr><td>LIBRARY_PATH</td><td>用于在程序编译期间查找动态链接库时指定查找共享库的路径</td></tr><tr><td>LD_LIBRARY_PATH</td><td>用于在程序加载运行期间查找动态链接库时指定查找共享库的路径</td></tr><tr><td>INCLUDE</td><td>用于在程序编译期间查看头文件的路径</td></tr><tr><td>PBS_O_HOST</td><td>提交作业的主机名</td></tr><tr><td>PBS_O_WORKDIR</td><td>提交作业的工作路径</td></tr><tr><td>PBS_JOBID</td><td>作业被 PBS 系统指定的作业号</td></tr><tr><td>PBS_QUEUE</td><td>PBS 脚本在执行时的队列名</td></tr><tr><td>PBS_NODEFILE</td><td>PBS 系统指定的作业运行的节点名</td></tr></tbody></table>

在 shell 命令行界面中输入一个外部命令时，shell 必须搜索系统来找到对应的程序。`PATH` 环境变量定义了用于进行命令和程序查找的目录。例如，输出中显示了有 8 个可供 shell 用来查找命令和程序。`PATH` 中的目录使用冒号分隔。

```bash
[zhangzh@node01 ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin: 10 /sbin:/bin:/usr/games:/usr/local/games
[zhangzh@node01 ~]$
```

如果命令或者程序的位置没有包括在 `PATH` 变量中，那么如果不使用绝对路径的话，shell 是没法找到的。如果 shell 找不到指定的命令或程序，它会产生一个错误信息（<mark style="color:$success;">所以建议都使用绝对路径</mark>）：

```bash
[zhangzh@node01 ~]$ myprog
-bash: myprog: command not found $
```

登入 Linux 系统启动一个 bash shell 时，默认情况下 bash 会在几个文件中查找命令。这些文件叫作启动文件或环境文件。大多数 Linux 发行版只用这四个启动文件中的一到两个：

`$HOME/.bash_profile、$HOME/.bashrc、$HOME/.bash_login、$HOME/.profile`

这四个文件都以点号开头，这说明它们是隐藏文件（不会在通常的 `ls` 命令输出列表中出现）。它们位于用户的 `HOME` 目录下，所以每个用户都可以编辑这些文件并添加自己的环境变量，这些环境变量会在每次启动 bash shell 会话时生效。

当在登录时 `echo` 一些个性化的内容，如登录信息，应该将脚本添加在 `$HOME/.bash_profile` 中，而不得添加在 `$HOME/.bashrc` 中，因为在使用 `sftp` 等需要按行查看登录环境的命令时，`echo` 会打乱其读取的内容，导致连接失败。

{% hint style="info" %}
**ls命令（list files）** 可以打印出当前工作目录下的所有文件（目录/地址也是一种文件）。

**echo命令** 用于在 shell 中打印 shell 变量的值，或者直接输出指定的字符串。
{% endhint %}

## 服务查询

`systemctl status` 用于查看服务状态，显示特定服务的详细信息，包括当前是否正在运行、最后一次启动时间、PID、主机名称等。e.g.

```shell
[zhangzh@node01 ~]# systemctl status firewalld.service 
?.firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enable>
   Active: active (running) since Mon 2022-04-18 10:56:12 CST; 1 weeks 0 days ago
     Docs: man:firewalld(1)
 Main PID: 3056 (firewalld)
    Tasks: 2 (limit: 1645568)
   Memory: 40.3M
   CGroup: /system.slice/firewalld.service
           ?..3056 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork --nopid
```

## 地址与端口

* **地址**：地址通常指的是 IP 地址，它是用来唯一标识网络中的设备（例如计算机、路由器、服务器等）的，使得数据能够正确地发送和接收。IP 地址可以分为 IPv4 地址（如 `192.168.1.1` ）和 IPv6 地址（如 `2001:0db8:85a3:0000:0000:8a2e:0370:7334` ）。
* **端口**：端口是一个用来标识应用程序或服务的逻辑通道。在网络通信中，数据包通过端口来确定应该传递给哪个应用程序或服务。端口号是一个 16 位的数字，范围从 `0` 到 `65535`。其中，`0` 到 `1023` 的端口号是被预留给一些知名的服务（例如 HTTP 服务的端口号是 `80`，HTTPS 服务的端口号是 `443`）。一般情况下，用户自定义的应用程序会使用大于 `1023` 的端口号。

因此，地址和端口在网络通信中起着非常重要的作用，地址用于标识设备，而端口则用于标识设备上的应用程序或服务。

```sh
$ ifconfig        # 查看本机IP
$ netstat -aptn   # 查看本机端口号
$ ping ip         # 查看地址是否联通
$ telnet ip port  # 含端口号查看地址
```

## 路径与文件

**路径**是文件（目录也是文件）在 Linux 系统中的唯一位置。Linux 中路径分为两种：

* **绝对路径**：是完全限定名称从根目录 `/` 开始，指定到达唯一单个文件所需要遍历的每个子目录；
* **相对路径**： 仅指定从工作目录到达该文件所需的路径。

**cd命令**（change directory）用于改变当前工作目录，或切换到指定的路径。Shell 的后续相对路径操作（如 `ls`、`cp`）都将基于新目录执行。

{% code title="命令语法" %}

```bash
cd [目录路径（绝对路径和相对路径均可）]
```

{% endcode %}

如 `cd ~` 意为切换到家目录，`cd .` 切换至当前工作目录，`cd ..` 切换至工作目录的上一级目录。e.g.

```bash
[zhangzh@node01 ~]$ ll
总用量 32K
drwxr-xr-x  2 zhangzh ybj 4.0K 2022-11-03 17:41 asgamma
drwxr-xr-x  3 zhangzh ybj 4.0K 2025-12-04 23:26 bin
drwx------ 11 zhangzh ybj 4.0K 2024-04-06 21:27 grb
drwxr-xr-x 15 zhangzh ybj 4.0K 2026-01-04 14:38 other
drwx------ 10 zhangzh ybj 4.0K 2025-05-09 22:07 practice
drwxr-xr-x  8 zhangzh ybj 4.0K 2023-08-16 21:45 software
drwx------ 14 zhangzh ybj 4.0K 2025-11-16 12:26 wl
drwxr-xr-x 11 zhangzh ybj 4.0K 2023-09-19 13:59 wl_old
[zhangzh@node01 ~]$ cd bin
[zhangzh@node01 bin]$ ls
aqsub                  feng.C      pqsub         Style.C
askill_eos             fzyStyle.C  pv            subcondor
asremove               gqview      pv-1.8.5.tar  virtual-kill.py
astat_eos              kcondor     python        virtual-kill.sh
asub_eos               kill.sh     qcondor       virtual-stat.sh
compile                mqdel       qdl           virtual-sub.sh
coreutils-8.32         mv          rootc         wcdaEnv.sh
coreutils-8.32.tar.xz  node        rootcc        xm
cp                     npm         sqsub         yqsub
[zhangzh@node01 bin]$ cd ..
[zhangzh@node01 ~]$ ls
asgamma  bin  grb  other  practice  software  wl  wl_old
[zhangzh@node01 ~]$ 
```

## 通配符与正则表达

在前文的介绍中，已或多或少涉及了一些通配符与正则表达，二者是 Linux 中最强大的工具，虽然规则很多，但是值得反复学习和使用，受益终身。

**通配符用于匹配文件名。**&#x5982; `find, ls, cp, mv` 等命令支持通配符查找文件名。

<table><thead><tr><th width="83.1875" align="center">符号</th><th>解释及示例</th></tr></thead><tbody><tr><td align="center"><code>*</code></td><td>匹配任何字符。<mark style="color:$info;">e.g. <code>rm *.txt</code> 删除当前目录下的所有以 <code>.txt</code> 结尾的文件。</mark></td></tr><tr><td align="center"><code>?</code></td><td>匹配单个字符。<mark style="color:$info;">e.g. <code>ls file?.txt</code> 将匹配 <code>file1.txt</code>、<code>file2.txt</code> 等文件。</mark></td></tr><tr><td align="center"><code>[-]</code></td><td>范围匹配。<mark style="color:$info;">e.g. <code>rm [a-z].txt</code> 删除当前目录下的包含小写字母的文件，举一反三，<code>[a-zA-Z0-9]</code> 意为匹配所有大小写字母和阿拉伯数字。</mark></td></tr><tr><td align="center"><code>{,}</code></td><td>选项匹配。<mark style="color:$info;">e.g. <code>touch {a..z}.txt</code> 按字母顺序创建名为 <code>a.txt</code> 到 <code>z.txt</code>，删除同理。<code>touch {a.txt,b.txt}</code> 创建名为 <code>a.txt</code> 和 <code>b.txt</code> 的文件。<code>cp a{.c,.c.bak}</code> 为 <code>a.c</code> 创建名为 <code>a.c.bak</code> 的备份文件。</mark></td></tr><tr><td align="center"><code>\</code></td><td>转义字符。<mark style="color:$warning;">转为表达字符的原始含义用。e.g.</mark> <mark style="color:$info;"><code>ls \*.txt</code> 将匹配以 <code>*.txt</code> 结尾的文件。</mark></td></tr><tr><td align="center"><code>!</code></td><td>取反匹配。<mark style="color:$info;">e.g. <code>[!abc]</code> 表示不包含 <code>abc</code> 中的任何字母。</mark></td></tr><tr><td align="center"><code>^</code></td><td>同上。</td></tr></tbody></table>

<details>

<summary>e.g. <strong>通配符实例</strong></summary>

```bash
[zhangzh@node01 ~]$ touch lab{1..11}
[zhangzh@node01 ~]$ ll
total 4
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab1
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab10
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab11
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab2
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab3
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab4
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab5
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab6
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab7
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab8
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab9
drwx------ 2 zhangzh ybj 4096 May  7 18:16 linux
[zhangzh@node01 ~]$ rm -rf lab1?
[zhangzh@node01 ~]$ ll
total 4
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab1
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab2
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab3
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab4
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab5
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab6
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab7
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab8
-rw-r--r-- 1 zhangzh ybj    0 May  8 13:43 lab9
drwx------ 2 zhangzh ybj 4096 May  7 18:16 linux
[zhangzh@node01 ~]$ ls l?b1
lab1
[zhangzh@node01 ~]$ ls l*b1
laab1  lab1
[zhangzh@node01 ~]$ ls l?b*
lab1  lab11  lab2  lab3  lab4  lab5
[zhangzh@node01 ~]$ ls lab*    # 取反查找
lab1  lab11  lab2  lab3  lab4  lab5
[zhangzh@node01 ~]$ ls lab[^1]
lab2  lab3  lab4  lab5
[zhangzh@node01 ~]$ rm -rf lab*
[zhangzh@node01 ~]$ ll
total 4
drwx------ 2 zhangzh ybj 4096 May  7 18:16 linux
```

</details>

**正则表达式元字符有字符匹配、匹配次数、位置锚定、分组**。主要是处理文本里的内容，用来匹配文本里的字符串，针对文件内容的文本过滤工具里，大都用到正则表达式，如 `grep, sed, awk, vim, less, nginx, varnish` 等命令，均支持正则表达式。

<table data-full-width="false"><thead><tr><th width="97" align="center">符号</th><th>解释</th></tr></thead><tbody><tr><td align="center"><code>.</code></td><td>匹配任意单个字符。</td></tr><tr><td align="center"><code>*</code></td><td>匹配 0 个或多个前面的字符。</td></tr><tr><td align="center"><code>+</code></td><td>匹配 1 个或多个前面的字符。</td></tr><tr><td align="center"><code>?</code></td><td>匹配 1 次或 0 次前面的字符。</td></tr><tr><td align="center"><code>()</code></td><td>分组过滤，被括起来的内容表示一个整体。</td></tr><tr><td align="center"><code>|</code></td><td>匹配多个模式中的一个。</td></tr><tr><td align="center"><code>^</code></td><td>匹配行的开头。<mark style="color:$info;">e.g. <code>grep '^start' file.txt</code> 将匹配以 <code>start</code> 开头的行。</mark></td></tr><tr><td align="center"><code>$</code></td><td>匹配行的结尾。<mark style="color:$info;">e.g. <code>grep 'end$' file.txt</code> 将匹配以 <code>end</code> 结尾的行。</mark></td></tr><tr><td align="center"><code>\b</code></td><td>匹配单词的边界。<mark style="color:$info;">e.g. <code>grep '\bword\b' file.txt</code> 将匹配独立的单词 <code>word</code>。</mark></td></tr><tr><td align="center"><code>\d</code></td><td>匹配数字字符。<mark style="color:$info;">e.g. <code>grep '\d+' file.txt</code> 将匹配一个或多个数字。</mark></td></tr><tr><td align="center"><code>\w</code></td><td>匹配字母数字字符。<mark style="color:$info;">e.g. <code>grep '\w+' file.txt</code> 将匹配一个或多个字母数字字符。</mark></td></tr><tr><td align="center"><code>\s</code></td><td>匹配空白字符。<mark style="color:$info;">e.g. <code>grep 'line\s+' file.txt</code> 将匹配以 <code>line</code> 开头的行，并跟随一个或多个空白字符。</mark></td></tr><tr><td align="center"><code>{n}</code></td><td>匹配前面的元素恰好 <code>n</code> 次。<mark style="color:$info;">e.g. <code>grep 'a{3}' file.txt</code> 将匹配 <code>aaa</code>。</mark></td></tr><tr><td align="center"><code>{n,}</code></td><td>匹配前面的元素至少 <code>n</code> 次。<mark style="color:$info;">e.g. <code>grep 'a{2,}' file.txt</code> 将匹配至少两个连续的 <code>a</code>。</mark></td></tr><tr><td align="center"><code>{n, m}</code></td><td>匹配前面的元素至少 <code>n</code> 次，但不超过 <code>m</code> 次。<mark style="color:$info;">e.g. <code>grep 'a{2,4}' file.txt</code> 将匹配两个到四个连续的 <code>a</code>。</mark></td></tr></tbody></table>

## 根目录结构

Linux 的根目录通常有这些文件构成，它们的作用分别是：

```
/bin       存放普通用户所使用的命令；以二进制（binary）存储
/boot      操作系统的启动文件；
/dev       系统可识别的设备目录；
/etc       服务配置文件，yum安装地址；
/home      普通账号的家目录；
/lib       存放库文件.so；
/media     软硬盘挂载点；
/opt       安装大型软件；
/proc/sys  虚拟内存，正在运行的信息被映射至这两个目录；
/tmp       临时文件存放目录；
/var       日志目录
```

## 软件编译

用户从 GitHub 或官网下载的开源软件通常只是**源代码**。因此必须使用编译器将文本代码转化为可执行程序，这个过程就叫做**编译**（Compilation）。

GNU 编译器套件 GCC 是 Linux 操作系统中最核心、最标准的编译器套件。它支持多种主流编程语言：

* `gcc`：专门用于编译 C 语言程序。
* `g++`：专门用于编译 C++ 语言程序（在高能物理数据分析中极高频使用）。
* `gfortran`：用于编译 Fortran 语言程序（很多传统物理模拟软件仍在使用）。

#### **源码安装“三连”机制：**

当用户下载了一个带有 `configure` 文件的开源软件时，需要通过以下规范的“三连”命令进行编译安装：

```
[zhangzh@node01 ~]$ ./configure
[zhangzh@node01 ~]$ make
[zhangzh@node01 ~]$ make install
```

1. `./configure`，**环境检查与个性化配置**。脚本会自动检测 Linux 系统里有没有安装所需的编译器、依赖库是否齐全、CPU 架构。如果想指定安装位置，需要使用 `--prefix` 参数指定自定义安装路径：`[zhangzh@node01 ~]$ ./configure --prefix=/home/zhangzh/my_software`
2. `make` **编译**。命令会读取源码目录下的 `Makefile` 文件（该文件在第一步成功后自动生成），然后调用后端的 `gcc` 或 `g++` 编译器，将源代码文件正式编译成二进制目标文件。当用户的 CPU 有 8 个核心，可以使用 `make -j8`，它允许 8 个线程同时编译，速度能提升数倍。
3. `make install` **文件拷贝与分发**。将上一步编译好的可执行文件、动态链接库（`.so`）以及头文件（`.h`），从源码目录正式拷贝到用户指定的安装目录中。如果第一步没有指定 `--prefix`，软件会默认安装到 `/usr/local/bin` 中，此时执行该命令必须在前面加上管理员权限 `sudo make install`。

#### 配置环境变量

软件安装完成后，需要为系统指定路径。这就需要在本地的 `~/.bashrc` 中配置环境变量。假设用户将软件安装在了 `/home/zhangzh/my_software` 目录下，打开 `~/.bashrc` 并追加以下标准配置：

```
# 1. 让系统能够直接运行该软件的命令行工具
export PATH=/home/zhangzh/my_software/bin:$PATH

# 2. 让系统在编译其他程序时，能找到该软件的头文件（Include）
export C_INCLUDE_PATH=/home/zhangzh/my_software/include:$C_INCLUDE_PATH
export CPLUS_INCLUDE_PATH=/home/zhangzh/my_software/include:$CPLUS_INCLUDE_PATH

# 3. 让系统在运行期间，能动态加载该软件的库文件（Library）
export LD_LIBRARY_PATH=/home/zhangzh/my_software/lib:$LD_LIBRARY_PATH
```

保存退出后，在终端执行 `source ~/.bashrc` 使配置立即生效，完成。

**参考：**

* [一个简单的 make & makefile 教程](https://zhuanlan.zhihu.com/p/92010728)
* [让世界再多一份 GNU m4 教程](https://segmentfault.com/a/1190000004104696)

## 添加媒体

Linux 中，「媒体」指的是存储介质，如光盘、USB 闪存驱动器、硬盘等，用于安装、存储和传输数据。媒体通常需要被挂载到系统中，以便用户访问和操作。步骤是（临时挂载）：

1. 插入媒体（u盘）到计算机，通常它的硬件名称为：`sda1`，可以用 `fdisk -l` 来查看当前的硬件名称。
2. 在 `mnt` 目录下先建立一个 usb 的目录，如 `# mkdir /mnt/usb`。
3. 挂载媒体：`mount -t vfat /dev/sda1 /mnt/usb`。
4. 卸载媒体：`umount /mnt/usb`。
5. 删除 usb 目录：`rm -rf /mnt/usb`。

非临时挂载需要在 `vi /etc/fstab` 中修改配置，配置在重启后才能生效。

当发现无法卸载某个媒体，尝试使用 `fuser -km` 关闭所有进程。

## 配置别名

**alias命令** 创建常用命令的快捷形式，二者输入效果等价。例如：`alias ll='ls -latr'`，创建了一个命令别名 `ll` 等价于 `ls -latr`，每次输入 `ll`，终端显示效果和 `ls -latr` 一样。

<mark style="color:$warning;">每次配置别名仅在当前 bash 中生效，</mark>把别名配置保存在 `~/.bashrc` 中将全局生效，具体参考这篇[文章](http://superuser.com/a/183980/7106)。
