# 类 Unix 工作环境基础

虽然 MC 差不多可以让你做任何事情，但学会从 shell 提示下使用命令行工具也是非常重要的，可以让你变得熟悉类 Unix 工作环境。

## 登录 shell

因登录 shell 可以被一些系统初始化程序使用，请谨慎的把登录 shell 保持为 `bash`或者其他POSIX shell 例如zsh ，并避免把它转换为 `chsh`。

|软件包|POSIX shell|说明|
|-|-|-|
|bash|是|Bash: GNU Bourne Again SHell (事实上的标准)|
|bash-completion|N/A|bash shell 编程补全|
|dash|是|Debian Almquist Shell, 擅长 shell 脚本|
|zsh|是|Z shell:有许多增强的标准 shell|
|tcsh|No|TENEX C Shell: 一个 Berkeley csh 的增强版本|
|mksh|是|Korn shell 的一个版本|
|csh|No|OpenBSD C Shell, Berkeley csh 的一个版本|
|sash|是|有内置命令的 Stand-alone shell (并不意味着标准的 "/bin/sh")|
|ksh|是|Korn shell的真正的 AT&T 版本|
|rc|No|AT&T Plan 9 rc shell 的一个实现|
|posh|是|Policy-compliant Ordinary SHell 策略兼容的普通 shell(pdksh 派生)|
|fish|No|fish旨在成为一个比其他shell交互性更强、用户体验更好的shell|

虽然类 POSIX 共享基本语法，但他们在 shell 变量和全局扩展等基本事情上，行为可以不同。细节请查阅他们的文档。

在本教程中，交互式的 shell 总是指 `bash`.

## 定制 bash

你可以通过“`~/.bashrc`”来定制`bash`(1)的行为。

尝试下列例子。

```Shell
# enable bash-completion
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

# CD upon exiting MC
. /usr/lib/mc/mc.sh

# set CDPATH to a good one
CDPATH=.:/usr/share/doc:~:~/Desktop:~
export CDPATH

PATH="${PATH+$PATH:}/usr/sbin:/sbin"
# set PATH so it includes user's private bin if it exists
if [ -d ~/bin ] ; then
  PATH="~/bin${PATH+:$PATH}"
fi
export PATH

EDITOR=vim
export EDITOR
```

你可以在第 9 章 系统技巧中的第 “有颜色输出的命令”找到更多关于bash的定制技巧。

bash-completion 软件包能够让 bash 进行命令补全.

## ZSH

zsh是我个人更为推荐的shell,在安装插件之后能实现自动补全，自动记忆以及高亮命令。

zsh几乎100%兼容bash的操作

具体教程不在这里赘述，请移步-→

## 特殊按键

在 [类Unix](https://zh.wikipedia.org/wiki/Unix-like) 环境，有一些具有特殊含义的按键。请注意，普通的Linux字符控制台，只有左手边的 `Ctrl` 和 `Alt` 键可以正常工作。其中有几个值得记住的按键。

|快捷键|描述|
|-|-|
|Ctrl-U|删除光标前到行首的字符|
|Ctrl-H|删除光标前的一个字符|
|Ctrl-D|终止输入（如果你在使用 shell，则退出 shell）|
|Ctrl-C|终止一个正在运行的程序|
|Ctrl-Z|通过将程序移动到后台来暂停程序|
|Ctrl-S|停止屏幕输出|
|Ctrl-Q|激活屏幕输出|
|Ctrl-Alt-Del|重启/关闭系统，参见 inittab(5)|
|左 Alt 键（可选择同时按下 Windows-key）|Emacs 和相似 UI 的元键（meta-key）|
|Up-arrow 向上方向键|开始在bash 中查看命令历史|
|Ctrl-R|开始在 bash 的增量命令历史中搜索|
|Tab|在 bash 命令行中补全文件名|
|Ctrl-V Tab|在 bash 命令行中输入 Tab 而不是进行补全|

## 鼠标操作

[Debian 系统针对文本的鼠标操作混合 2 种风格](https://specifications.freedesktop.org/clipboards-spec/clipboards-latest.txt)，外加一些新的方法：

- 传统的 Unix 鼠标操作方式：

  - 使用 3 个按钮（单击）

  - 使用主要键

  - 由 X 应用，如 `xterm`，以及文本应用在控制台中使用

- 现代 GUI（图形用户界面）鼠标操作方式：

  - 使用 2 个按钮（拖动 + 单击）

  - 使用主要键和剪贴板

  - 用于现代的 GUI（图形用户界面）应用，比如 `deepin-terminal`

|操作|响应|
|-|-|
|左击并拖动鼠标|主要键的选择作为选择范围|
|单击左键|主要键的位置作为选择范围的开头|
|单击右键（传统方式）|主要键的位置作为选择范围的结尾|
|单击右键（现代方式）|依赖上下文的菜单（剪切、拷贝、粘贴）|
|点击中键或者 Shift-Ins|在光标处插入主要键的选择|
|Ctrl-X|剪切主要键的选择到剪贴板|
|Ctrl-C (在终端是 Shift-Ctrl-C )|拷贝主要键的选择到剪贴板|
|Ctrl-V (在终端是 Shift-Ctrl-V )|粘贴剪切板的内容到光标处|

这里，主要键的选择会高亮文本范围。在终端程序内，使用 `Shift-Ctrl-C` 来代替，这样可以避免终止一个运行的程序。

在现代滚轮鼠标上的中央滚轮，被认为是中间键，并可以被当做中间键使用。在 2 键鼠标系统的情况下，同时按左键和右键就相当于按中间键。

为了在 Linux 字符控制台中使用鼠标，您需要让 `gpm`(8) 作为后台守护进程（daemon）运行。

## 分页程序

`less`(1) 命令是一个增强版的分页程序（文件内容查看器）。它按照指定的命令参数或标准输出来读取文件。在用 `less` 命令查看的时候如果需要帮助可以按 “`h`”。它的功能比 `more`(1) 命令更丰富，通过在脚本的开头执行 "`eval $(lesspipe)`" 或 "`eval $(lessfile)`" 它的功能还能变得更加强大。详细请参考 "`/usr/share/doc/less/LESSOPEN`"。 "`-R`" 选项可以实现原始的字符输出还可以启用 ANSI 颜色转义序列。详细请参考 `less`(1)。

## 文本编辑器

在使用类 Unix 系统过程中， 各种类似于[Vim](https://zh.wikipedia.org/wiki/Vim_(text_editor)) 或 [Emacs](https://zh.wikipedia.org/wiki/Emacs)的工具，你应该精通其中的一个。

我认为习惯于使用 Vim 命令是一个明智的选择，因为 Linux/Unix 系统里一般都附带了 Vi 编辑器。 (实际上最初的 `vi` 以及后来的 `nvi` 这类工具程序很常见。因为在 Vim 里提供了`F1`帮助键，在同类工具中它的功能更强大，所以我选择 Vim 而不是其它新出的一些工具。)

假设你不是用 [Emacs](https://zh.wikipedia.org/wiki/Emacs) 就是用 [XEmacs](https://zh.wikipedia.org/wiki/XEmacs) 作为你的编辑器，
其实还有更好的选择，尤其是在编程的时候。 Emacs 还有很多其他的特点，包括新手导读，目录编辑器，邮件客户端等等。当编写脚本或程序的时候，
它能自动识别当前工作模式所对应的格式，让使用更加便利。一些人甚至坚持认为 Linux 系统里最需要配备的就是 Emacs。花十分钟来学习 Emacs
可以为后面的工作剩下更多时间。在此强烈推荐学习使用 Emacs 时候直接使用 GNU Emacs 参考手册。

在实践应用中所有这些程序都会有一个教程，输入 "`vim`" 和F1键就可以启动Vim。建议你最好阅读一下前面的 35 行。移动光标到 "`|tutor|`" 并按 `Ctrl-]` 就可以看到在线培训教程。

其实很多人初次接触vim的时候觉得vim有点反人类，一开始连退出都不知道在那里，但是用熟悉了就真香了。

好的编辑器，像 Vim 和 Emacs，可以处理 UTF-8 及其它不常用编码格式的文本。有个建议就是在 GUI（图形用户界面） 环境下使用 UTF-8 编码，并安装要求的程序和字体。编辑器里可以选择独立于 GUI（图形用户界面）环境的编码格式。关于多字节文本可以查阅参考文档。

GUI文本编辑器deepin内置了deepin-editor,是非常好用的，还有宇宙第一ide——装了插件的vscode（见vscode的词条）

## 设置默认文本编辑器

Debian 有许多不同的编辑器。我们建议安装上面提到的 `vim` 软件包。

Debian 通过命令“`/usr/bin/editor`”提供了对系统默认编辑器的统一访问，因此其它程序（例如 `reportbug`(1)）可以调用它。你可以通过下列命令改变它。

```Shell
sudo update-alternatives --config editor
```

对于新手，我建议使用“`/usr/bin/vim.basic`”代替“`/usr/bin/vim.tiny`”，因为它支持格式高亮。

## 使用

使用vim我个人认为是很难在这一点页面说完的，所以本着不重复造轮子的思想，在这放出基本命令和优质中文教程：

|模式|按键|操作|
|-|-|-|
|普通|:help|only|
|普通|:e filename.ext|打开新的缓冲区来编辑 filename.ext|
|普通|:w|把目前的缓冲区改写到原始文件|
|普通|:w filename.ext|写入当前缓冲区到 filename.ext|
|普通|:q|退出 vim|
|普通|:q!|强制退出 vim|
|普通|:only|关闭所有其它分割打开的窗口|
|普通|:set nocompatible?|检查 vim 是否在完全的 nocompatible 模式|
|普通|:set nocompatible|设置 vim 到完全的 nocompatible 模式|
|普通|i|进入 插入 模式|
|普通|R|进入 替代 模式|
|普通|v|进入 可视 模式|
|普通|V|进入 可视 行 模式|
|普通|Ctrl-V|进入 可视 块 模式|
|除了 TERMINAL-JOB 外|ESC-键|进入 普通 模式|
|普通|:term|进入 TERMINAL-JOB 模式|
|TERMINAL-NORMAL|i|进入 TERMINAL-JOB 模式|
|TERMINAL-JOB|Ctrl-W N (或者 Ctrl-\ Ctrl-N)|进入 TERMINAL-NORMAL 模式|
|TERMINAL-JOB|Ctrl-W :|在TERMINAL-NORMAL 模式里进入Ex-模式|

请使用 "`vimtutor`" 程序来学习 `vim`，通过一个交互式的指导课程。

`vim` 程序基于 **模式** 输入的按键来改变它的行为。在 `插入`-模式和 `替代`-模式下，输入的按键大部分进入了缓冲区。移动光标大部分在 `普通`-模式下完成。交互选择在 `可视`-模式下完成。在`普通`-模式下输入 "`:`" ，改变它的 **模式** 进入到 `Ex`-模式。 `Ex`-接受命令。

## 记录 shell 活动

shell 命令的输出有可能滚动出了屏幕，并可能导致你无法再查看到它。将shell活动记录到文件中再来回顾它是个不错的主意。当你执行任何系统管理任务时，这种记录是必不可少的。

记录 shell 活动的基本方法是在`script`(1)下运行 shell。

尝试下列例子

```Shell
$ script
Script started, file is typescript
```

在`script`下使用任何 shell 命令。

按`Ctrl-D`来退出`script`。

```Shell
vim typescript
```

## 基本的 Unix 命令

让我们来学习基本的 Unix 命令。在这里，我指的是一般意义上的“UNIX”。任何 UNIX 克隆系统通常都会提供等价的命令。deepin 系统也不例外。如果有一些命令不像你想的那样起作用，请不要担心。如果 shell 中使用了别名，其对应的命令输出会不同。这些例子并不意味着要以这个顺序来执行。

尝试使用非特权用户账号来使用下列的命令。

|命令|说明|
|-|-|
|pwd|显示当前/工作目录的名称|
|whoami|显示当前的用户名|
|id|显示当前用户的身份（名称、uid、gid和相关组）|
|file foo|显示“foo”文件的文件类型|
|type -p commandname|显示命令的文件所处位置“commandname”|
|which commandname|同上|
|type commandname|显示“commandname”命令的相关信息|
|apropos key-word|查找与“key-word”有关的命令|
|man -k key-word|同上|
|whatis commandname|用一行解释 “commandname” 命令|
|man -a commandname|显示“commandname”命令的解释（Unix 风格）|
|info commandname|显示“commandname”命令相当长的解释（GNU风格）|
|ls|显示目录内容（不包含以 . 点号开头的文件和目录）|
|ls -a|显示目录内容（包含所有文件和目录）|
|ls -A|显示目录内容（包含几乎所有文件和目录，除了“..”和“.”）|
|ls -la|显示所有的目录内容，并包含详细的信息|
|ls -lai|显示所有的目录内容，并包含inode和详细的信息|
|ls -d|显示当前目录下的所有目录|
|tree|使用树状图显示目录内容|
|lsof foo|列出处于打开状态的文件 "foo"|
|lsof -p pid|列出被某进程打开的文件: "pid"|
|mkdir foo|在当前目录中建立新目录“foo”|
|rmdir foo|删除当前目录中的“foo”目录|
|cd foo|切换到当前目录下或变量“$CDPATH”中的“foo”目录|
|cd /|切换到根目录|
|cd|切换到当前用户的家目录|
|cd /foo|切换到绝对路径为“/foo”的目录|
|cd ..|切换到上一级目录|
|cd ~foo|切换到用户“foo”的家目录|
|cd -|切换到之前的目录|
|</etc/motd pager|使用默认的分页程序来显示“/etc/motd”的内容|
|touch junkfile|建立一个空文件“junkfile”|
|cp foo bar|将一个现有文件“foo”复制到一个新文件“bar”|
|rm junkfile|删除文件“junkfile”|
|mv foo bar|将一个现有文件“foo”重命名成“bar”（“bar”必须不存在）|
|mv foo bar|将一个现有文件“foo”移动到新的位置“bar/foo”（必须存在“bar”目录）|
|mv foo bar/baz|移动一个现有文件“foo”到新位置并重命名为“bar/baz”（必须存在“bar”目录，且不存在“bar/baz文件”）|
|chmod 600 foo|使其他人无法读写现有文件“foo”（并且所有人都无法执行该文件）|
|chmod 644 foo|使其他人对现有文件“foo”可读但不可写（并且所有人都无法执行该文件）|
|chmod 755 foo|使其他人对“foo”可读而不可写（并且所有人都能执行该文件）|
|find . -name pattern|使用 shell “pattern” 查找匹配的文件名（速度较慢）|
|locate -d . pattern|使用 shell “pattern” 查找匹配的文件名（速度较快，使用定期生成的数据库）|
|grep -e "pattern" *.html|在当前目录下以“.html”结尾的所有文件中，查找匹配“pattern”的文件并显示|
|top|全屏显示进程信息，输入“q”退出|
|ps aux|pager|
|ps -ef|pager|
|ps aux|grep -e "[e]xim4*"|
|ps axf|pager|
|kill 1234|杀死ID为“1234”的进程|
|gzip foo|使用 Lempel-Ziv 编码（LZ77）将“foo”压缩为“foo.gz”|
|gunzip foo.gz|将“foo.gz”解压为“foo”|
|bzip2 foo|使用 Burrows-Wheeter 块排序压缩算法和 Huffman 编码将“foo”压缩为“foo.bz2”（压缩效果比gzip更好）|
|bunzip2 foo.bz2|将“foo.bz2”解压为“foo”|
|xz foo|使用 Lempel-Ziv-Markov 链算法将“foo”压缩为“foo.xz”（压缩效果比bzip2更好）|
|unxz foo.xz|将“foo.xz”解压为“foo”|
|tar -xvf foo.tar|从“foo.tar”档案中提取文件|
|tar -xvzf foo.tar.gz|从被gzip压缩过的“foo.tar.gz”档案中提取文件|
|tar -xvjf foo.tar.bz2|从“foo.tar.bz2”档案中提取文件|
|tar -xvJf foo.tar.xz|从“foo.tar.xz”档案中提取文件|
|tar -cvf foo.tar bar/|将目录“bar/”中的内容打包到“foo.tar”档案中|
|tar -cvzf foo.tar.gz bar/|将目录 “bar/” 中的内容打包并压缩成 “foo.tar.gz” 文件|
|tar -cvjf foo.tar.bz2 bar/|将目录“bar/”中的内容打包到“foo.tar.bz2”档案中|
|tar -cvJf foo.tar.xz bar/|将目录”bar/“中的内容打包到”foo.tar.xz“档案中|
|zcat README.gz|pager|
|zcat README.gz > foo|将“README.gz”解压后的内容输出到文件“foo”中|
|zcat README.gz >> foo|将“README.gz”解压后的内容添加到文件“foo”的末尾（如果文件不存在，则会先建立该文件）|

Unix 有一个惯例，以“.”开头的文件将被隐藏。它们一般为包含了配置信息和用户首选项的文件。

  对于cd命令，参见builtins(7)。

  基本的 Debian 系统的默认分页程序是 more(1)，它无法往回滚动。通过命令 “apt-get install less" 安装 less 软件包后，less(1) 会成为默认的分页程序，它可以通过方向键往回滚动。

  "[" 和"]" 在正则表达式 "ps aux | grep -e "[e]xim4*"" 命令中，可以避免grep在结果中排除它自己， 正则表达式中的 "4*" 意思是空或字符"4" ，这样可以让 grep 既找到 "exim" 也找到 "exim4"。 虽然 "*" 可以用于命令名称匹配和正则表达式中，但是它们的含义是不一样的。欲详细了解正则表达式可以参考 grep(1)。

作为训练，请使用上述的命令来遍历目录并探究系统。如果你有任何有关控制台命令的问题，请务必阅读手册。

尝试下列例子

```Shell
man man
man bash
man builtins
man grep
man ls
```

手册的风格可能让人有点难以习惯，因为它们都相当简洁，尤其是比较老旧、非常传统的那些手册。但是，一旦你习惯了它，你来欣赏它们的简洁。

请注意，许多 类 Unix 命令（包含来自 GNU 和 BSD 的）都可以显示简短的帮助信息，你可以使用下列的其中一种方式来查看它（有时不带任何参数也可以）。

```Shell
commandname --help
$ commandname -h
```
