Skip to content

Command-line Environment(命令行环境)

我们已经使用 shell 一段时间了,但是到目前为止我们的关注点主要集中在使用不同的命令上面。现在,我们将会学习如何同时执行多个不同的进程并追踪它们的状态、如何停止或暂停某个进程以及如何使进程在后台运行。

我们还将学习一些能够改善您的 shell 及其他工具的工作流的方法,这主要是通过定义别名或基于配置文件对其进行配置来实现的。这些方法都可以帮您节省大量的时间。例如,仅需要执行一些简单的命令,我们就可以在所有的主机上使用相同的配置。我们还会学习如何使用 SSH 操作远端机器。

任务控制

某些情况下我们需要中断正在执行的任务,比如当一个命令需要执行很长时间才能完成时(假设我们在使用 find 搜索一个非常大的目录结构)。大多数情况下,我们可以使用 Ctrl-C 来停止命令的执行。但是它的工作原理是什么呢?为什么有的时候会无法结束进程?

结束进程

您的 shell 会使用 UNIX 提供的信号机制执行进程间通信。当一个进程接收到信号时,它会停止执行、处理该信号并基于信号传递的信息来改变其执行。就这一点而言,信号是一种 软件中断

在上面的例子中,当我们输入 Ctrl-C 时,shell 会发送一个 SIGINT 信号到进程。

下面这个 Python 程序向您展示了捕获信号 SIGINT 并忽略它的基本操作

python
#!/usr/bin/env python
import signal, time

def handler(signum, time):
    print("\nI got a SIGINT, but I am not stopping")

signal.signal(signal.SIGINT, handler)
i = 0
while True:
    time.sleep(.1)
    print("\r{}".format(i), end="")
    i += 1

这个程序会一直打印数字,并在接收到 SIGINT 信号时忽略它。

更加优雅地退出信号。为了发出这个信号我们需要使用 kill 命令. 例如我们可以kill -STOP %1他的意思是暂停第一个进程

终端复用器

有时我们需要同时运行多个命令,但是我们又不想在每个命令之间切换。这时我们可以使用终端复用器。

tmux

tmux 是一款优秀的终端复用器。它可以让我们在一个终端窗口中同时运行多个命令,并且可以随时暂停或恢复它们。

安装 tmux 非常简单,只需要在终端中运行 sudo apt-get install tmux 即可。

使用 tmux 的基本命令有:

  • tmux new -s <session-name> 创建一个新的会话
  • tmux attach -t <session-name> 进入一个已存在的会话
  • tmux ls 列出所有会话
  • tmux kill-session -t <session-name> 关闭一个会话

这是一份 tmux 详细教学

别名

alias 命令shell 中的一个命令,它可以为一个命令或一组命令创建别名。这样,我们就可以使用简短的命令来执行我们经常使用的命令。

例如,我们可以为 ls 命令创建别名 ll 来显示文件和目录的详细信息。

bash
alias ll='ls -l'

我们还可以为 cd 命令创建别名 .. 来快速回到上级目录。

bash
alias..='cd ..'

这样,我们就可以使用 ll 命令来显示文件和目录的详细信息,而 .. 命令则可以快速回到上级目录。

我们还可以为 git 命令创建别名,这样我们就可以使用简短的命令来执行常用的 git 命令。

bash
alias gco='git checkout'
alias gbr='git branch'
alias gpl='git pull'
alias gplr='git pull --rebase'
alias gst='git status'
alias glog='git log'

值得注意的是,在默认情况下 shell 并不会保存别名。为了让别名持续生效,您需要将配置放进 shell 的启动文件里,像是 .bashrc 或 .zshrc,下一节我们就会讲到。

Dotfiles(配置文件)

Dotfiles 是指以 . 开头的文件,这些文件包含了 shell 的配置信息。这些文件通常位于用户目录下,例如 ~/.bashrc~/.zshrc

shell 的配置也是通过这类文件完成的。在启动时,您的 shell 程序会读取很多文件以加载其配置项。根据 shell 本身的不同,您从登录开始还是以交互的方式完成这一过程可能会有很大的不同。

对于 bash 来说,在大多数系统下,您可以通过编辑 .bashrc.bash_profile 来进行配置。在文件中您可以添加需要在启动时执行的命令,例如上文我们讲到过的别名,或者是您的环境变量。

实际上,很多程序都要求您在 shell 的配置文件中包含一行类似 export PATH="$PATH:/path/to/program/bin" 的命令,这样才能确保这些程序能够被 shell 找到

还有一些其他的工具也可以通过 点文件 进行配置:

  • bash - ~/.bashrc, ~/.bash_profile
  • git - ~/.gitconfig
  • vim - ~/.vimrc~/.vim 目录
  • ssh - ~/.ssh/config
  • tmux - ~/.tmux.conf

我们应该如何管理这些配置文件呢,它们应该在它们的文件夹下,并使用版本控制系统进行管理,然后通过脚本将其 符号链接 到需要的地方。这么做有如下好处:

  1. 管理配置文件的便捷性:我们可以很容易地找到、修改和备份配置文件。
  2. 共享配置文件:我们可以将配置文件分享给其他人,让他们也能使用这些配置。
  3. 统一配置:我们可以为不同的机器配置不同的配置文件,从而实现统一的工作流。

远端设备

对于程序员来说,在他们的日常工作中使用远程服务器已经非常普遍了。如果您需要使用远程服务器来部署后端软件或您需要一些计算能力强大的服务器,您就会用到安全 shell(SSH)。和其他工具一样,SSH 也是可以高度定制的,也值得我们花时间学习它。

通过如下命令,您可以使用 ssh 连接到其他服务器:

bash
ssh username@remote_host

当然你也可以直接指定 IP 地址:

执行命令

ssh的一个经常被忽视的特性是他可以直接远程执行命令

比如:

bash
ssh username@remote_host ls

就可以直接在用 ssh 执行ls命令.

当然想要配合|(管道)就行

SSH 密钥

基于基于密钥的验证机制使用了密码学中的公钥,我们只需要向服务器证明客户端持有对应的私钥,而不需要公开其私钥。这样您就可以避免每次登录都输入密码的麻烦了秘密就可以登录。

密钥生成

使用该命令生成一对密钥:

bush
ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/id_rsa

如果您曾经配置过使用 SSH 密钥推送到 GitHub,那么可能您已经完成了 这里 介绍的这些步骤,并且已经有了一个可用的密钥对。要检查您是否持有密码并验证它,您可以运行 ssh-keygen -y -f /path/to/key.

基于密钥的认证机制

ssh 会查询 .ssh/authorized_keys 来确认那些用户可以被允许登录。您可以通过下面的命令将一个公钥拷贝到这里:

bash
cat ~/.ssh/id_rsa.pub | ssh username@remote_host 'cat >> ~/.ssh/authorized_keys'

如果支持 ssh-copy-id 的话,可以使用下面这种更简单的解决方案:

ssh-copy-id -i .ssh/id_ed25519.pub foobar@remote

通过 SSH 复制文件

使用ssh复制文件的方法有很多

  • ssh+tee,最简单的方法是执行ssh命令,然后然后通过这样的方法利用标准输入实现 cat localfile | ssh remote_server tee serverfile。回忆一下,tee 命令会将标准输出写入到一个文件;

  • scp当需要拷贝大量的文件或目录时,使用 scp 命令则更加方便,因为它可以方便的遍历相关路径。语法如下:scp path/to/local_file remote_host:path/to/remote_file

  • rsync如果需要同步多个目录,可以使用 rsync 命令,它可以高效的处理大量的文件。语法如下:rsync -avz path/to/local_dir remote_host:path/to/remote_dir-a 选项会保持所有文件属性,-v 选项会显示详细信息,-z 选项会压缩传输的结果。

端口转发

很多情况下我们都会遇到软件需要监听特定设备的端口。如果是在您的本机,可以使用 localhost:PORT127.0.0.1:PORT。但是如果需要监听远程服务器的端口该如何操作呢?这种情况下远端的端口并不会直接通过网络暴露给您

常见的情景是使用本地端口转发,即远端设备上的服务监听一个端口,而您希望在本地设备上的一个端口建立连接并转发到远程端口上。例如,我们在远端服务器上运行 Jupyter notebook 并监听 8888 端口。 然后,建立从本地端口 9999 的转发,使用 ssh -L 9999:localhost:8888 foobar@remote_server 。这样只需要访问本地的 localhost:9999 即可。

ssh 配置

我们已经介绍了很多参数。为它们创建一个别名是个好想法,我们可以这样做

bash
alias my_server="ssh -i ~/.id_ed25519 --port 2222 -L 9999:localhost:8888 foobar@remote_server

不过,更好的方法是使用 ~/.ssh/config.

bush
Host vm
    User foobar
    HostName 172.16.174.141
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    LocalForward 9999 localhost:8888

# 在配置文件中也可以使用通配符
Host *.mit.edu
    User foobaz

这么做的好处是,使用 ~/.ssh/config 文件来创建别名,类似 scprsync 和 mosh 的这些命令都可以读取这个配置并将设置转换为对应的命令行选项。

注意,~/.ssh/config 文件也可以被当作配置文件,而且一般情况下也是可以被导入其他配置文件的。不过,如果您将其公开到互联网上,那么其他人都将会看到您的服务器地址、用户名、开放端口等等。这些信息可能会帮助到那些企图攻击您系统的黑客,所以请务必三思。

服务器侧的配置通常放在 /etc/ssh/sshd_config。您可以在这里配置免密认证、修改 ssh 端口、开启 X11 转发等等。 您也可以为每个用户单独指定配置。

shell & 框架

框架 也可以改进您的 shell。比较流行的通用框架包括 prezto 或 oh-my-zsh。还有一些更精简的框架,它们往往专注于某一个特定功能,例如 zsh 语法高亮 或 zsh 历史子串查询。 像 fish 这样的 shell 包含了很多用户友好的功能,其中一些特性包括:

  • 向右对齐
  • 命令语法高亮
  • 历史子串查询
  • 基于手册页面的选项补全
  • 更智能的自动补全
  • 提示符主题

终端模拟器

和自定义 shell 一样,花点时间选择适合您的 终端模拟器 并进行设置是很有必要的。有许多终端模拟器可供您选择(这里有一些关于它们之间 比较 的信息)

您会花上很多时间在使用终端上,因此研究一下终端的设置是很有必要的,您可以从下面这些方面来配置您的终端:

  • 字体选择
  • 彩色主题
  • 快捷键
  • 标签页/面板支持
  • 回退配置
  • 性能(像 Alacritty 或者 kitty 这种比较新的终端,它们支持 GPU 加速)。