mit计算机教育中缺失的一课笔记:命令行环境

Chris      2022-02-12     294

关键词:

_写在前面:本篇内容来自于 MIT 推出的课程:计算机教育中缺失的一课,这门课程介绍了命令行、强大的文本编辑器的使用、使用版本控制系统提供的多种特性等等。中文课程主页。

本篇内容为第五节:命令行环境。本节的主要内容如下:

  1. 如何同时执行多个不同的进程并追踪它们的状态、如何停止或暂停某个进程以及如何使进程在后台运行。
  2. 一些能够改善 shell 及其他工具的工作流的方法,这主要是通过定义别名或基于配置文件对其进行配置来实现的
  3. 如何使用 SSH 操作远端机器

任务控制

结束进程

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

当我们输入 Ctrl-C 时,shell 会发送一个 SIGINT (interrupt program) 信号到进程。另外一个退出程序的信号:SIGQUIT (quit program) ,可以通过 Ctrl-\ 触发。

尽管 SIGINTSIGQUIT 都常常用来发出和终止程序相关的请求。SIGTERM 则是一个更加通用的、也更加优雅地退出信号。为了发出这个信号我们需要使用 kill 命令, 它的语法是: kill -TERM <PID>

暂停和后台执行进程

在终端中,键入 Ctrl-Z 会让 shell 发送 SIGTSTP 信号。此时,程序被挂起,并没有结束。

使用 jobs 命令,可以查看当前会话中的进程。当程序被挂起时,可以使用 fg 命令,将挂起的程序继续执行,或者使用 bg 命令,将程序放到后台继续执行。可以通过 jobs 打印结果中的进程标号,来引用某一个进程,如进程标号为 [1],后续可以通过 bg %1 的方式来将该进程在后台运行,也可以通过 kill %1 的方式杀掉该进程。

执行命令时,在最后添加 & ,可以直接让程序在后台执行。但是注意,这个进程仍然是终端的子进程,所以关闭终端时,这个进程也会被终止(此时发送的信号为 SIGHUP)。为了防止这种情况,可以在程序最前使用 nohup 程序:nohup command command_options,此时关掉终端,程序仍然会继续执行。

以下代码演示了这些命令:

❯ sleep 1000
^Z
[1]  + 60227 suspended  sleep 1000
❯ nohup sleep 2000 &
[2] 60237
appending output to nohup.out
❯ jobs
[1]  + suspended  sleep 1000
[2]  - running    nohup sleep 2000
❯ bg %1
[1]  - 60227 continued  sleep 1000
❯ jobs
[1]  - running    sleep 1000
[2]  + running    nohup sleep 2000
❯ kill %1
[1]  - 60227 terminated  sleep 1000
❯ jobs
[2]  + running    nohup sleep 2000
❯ kill -SIGHUP %2
❯ jobs
[2]  + running    nohup sleep 2000
❯ kill %2
[2]  + 60237 terminated  nohup sleep 2000
❯ jobs

以下为 Linux 系统中的信号列表,具体可以通过 man signal 来查询:

     No    Name         Default Action       Description
     1     SIGHUP       terminate process    terminal line hangup
     2     SIGINT       terminate process    interrupt program
     3     SIGQUIT      create core image    quit program
     4     SIGILL       create core image    illegal instruction
     5     SIGTRAP      create core image    trace trap
     6     SIGABRT      create core image    abort program (formerly SIGIOT)
     7     SIGEMT       create core image    emulate instruction executed
     8     SIGFPE       create core image    floating-point exception
     9     SIGKILL      terminate process    kill program
     10    SIGBUS       create core image    bus error
     11    SIGSEGV      create core image    segmentation violation
     12    SIGSYS       create core image    non-existent system call invoked
     13    SIGPIPE      terminate process    write on a pipe with no reader
     14    SIGALRM      terminate process    real-time timer expired
     15    SIGTERM      terminate process    software termination signal
     16    SIGURG       discard signal       urgent condition present on socket
     17    SIGSTOP      stop process         stop (cannot be caught or ignored)
     18    SIGTSTP      stop process         stop signal generated from keyboard
     19    SIGCONT      discard signal       continue after stop
     20    SIGCHLD      discard signal       child status has changed
     21    SIGTTIN      stop process         background read attempted from control terminal
     22    SIGTTOU      stop process         background write attempted to control terminal
     23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
     24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
     25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
     26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
     27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
     28    SIGWINCH     discard signal       Window size change
     29    SIGINFO      discard signal       status request from keyboard
     30    SIGUSR1      terminate process    User defined signal 1
     31    SIGUSR2      terminate process    User defined signal 2

终端多路复用(Terminal multiplexer)

来自维基百科的解释:终端多路复用器是一种软件应用程序,可用于在单个终端显示器,终端仿真器窗口,PC /工作站系统控制台或远程登录会话中多路复用几个单独的基于伪终端的登录会话,或者从终端分离和重新附加会话。最常用的终端多路复用软件为 tmux

tmux 中有三个非常重要的概念,分别为:会话、窗口和面板,关于其有很多重要的快捷键需要掌握:

  • 会话 - 每个会话都是一个独立的工作区,其中包含一个或多个窗口

    • 在终端输入 tmux 开始一个新的会话
    • tmux new -s NAME 以指定名称开始一个新的会话
    • tmux ls 列出当前所有会话
    • tmux 中输入 <C-b> d (detach),将当前会话分离
    • tmux a 重新连接最后一个会话。您也可以通过 -t NAME 来指定具体的会话
  • 窗口 - 相当于编辑器或是浏览器中的标签页,从视觉上将一个会话分割为多个部分

    • <C-b> c (create)创建一个新的窗口,使用 <C-d> 将其关闭
    • <C-b> N 跳转到第 N 个窗口,注意每个窗口都是有编号的
    • <C-b> p 切换到前一个窗口
    • <C-b> n 切换到下一个窗口
    • <C-b> , 重命名当前窗口
    • <C-b> w 列出当前所有窗口
  • 面板 - 像 vim 中的分屏一样,面板使我们可以在一个屏幕里显示多个 shell

    • <C-b> " 水平分割
    • <C-b> % 垂直分割
    • <C-b> <方向> 切换到指定方向的面板,<方向> 指的是键盘上的方向键
    • <C-b> z 切换当前面板的缩放(把当前面板缩放到最大)
    • <C-b> [ 开始往回卷动屏幕。可以按下空格键来开始选择,回车键复制选中的部分(非常有用)
    • <C-b> <空格> 在不同的面板排布间切换

别名设置

设置别名可以节省大量时间,将经常输入的命令设置为非常短的标记,用法为:alias alias_name="command arg1 arg2",以下是几个示例:

# 创建常用命令的缩写
alias ll="ls -lh"

# 能够少输入很多
alias gs="git status"
alias gc="git commit"
alias v="vim"

# 手误打错命令也没关系
alias sl=ls

# 重新定义一些命令行的默认行为
alias mv="mv -i"           # -i prompts before overwrite
alias mkdir="mkdir -p"     # -p make parent dirs as needed
alias df="df -h"           # -h prints human readable format

# 别名可以组合使用
alias la="ls -A"
alias lla="la -l"

# 在忽略某个别名
\ls
# 或者禁用别名
unalias la

# 获取别名的定义
alias ll
# 会打印 ll='ls -lh'

需要将想要设置别名的代码保存到 shell 的启动文件里,比如 .bashrc.zshrc

配置文件

一些常见的配置文件,位于用户目录下,以 . 开头:

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

管理这些配置文件推荐的方式:将这些文件都放到一个目录下,然后通过 git 控制版本,通过链接的方式,将文件链接到对应的文件上。这样的好处是显而易见的:如果有多台电脑需要配置,可以一键配置;并且更改配置也会同步到每一台电脑。

远端设备

通过 ssh 连接远程服务器,服务器可以通过 URL 指定(例如 bar.mit.edu),也可以使用 IP 指定(例如foobar@192.168.1.42)。

可以直接通过 ssh foobar@server ls 来在服务器上执行 ls 命令,只准备执行一条命令时非常方便。

使用秘钥连接远程服务器时,需要向服务器证明客户端持有对应的私钥。本地生成私钥:使用 ssh-keygen。将公钥传到服务器,有以下两种方式:

# 第一种方式,直接上传
cat .ssh/id_ed25519.pub | ssh foobar@remote 'cat >> ~/.ssh/authorized_keys'

# 第二种方式,需要本地支持 ssh-copy-id
ssh-copy-id -i .ssh/id_ed25519.pub foobar@remote

通过 SSH 复制文件,可以使用 scp 命令,语法为:scp path/to/local_file remote_host:path/to/remote_file。更好的是使用 rsync,它对 scp 进行了改进,可以检测本地和远端的文件以防止重复拷贝。

使用 SSH 端口转发

端口转发有两种:本地端口转发和远程端口转发。

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

SSH 配置文件

由于各种选项的存在,SSH 命令可能会很长,我们可以通过配置 ~/.ssh/config 文件,来保存服务器的配置,这个文件可以被 scprsync 等命令读取,转换为对应的命令行选项。配置示例:

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

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

课后练习

任务控制

  1. 我们可以使用类似 ps aux | grep 这样的命令来获取任务的 pid ,然后您可以基于 pid 来结束这些进程。但我们其实有更好的方法来做这件事。在终端中执行 sleep 10000 这个任务。然后用 Ctrl-Z 将其切换到后台并使用 bg 来继续它的执行。现在,使用 pgrep 来查找 pid 并使用 pkill 结束进程而不需要手动输入 pid。(提示:: 使用 -af 标记)。

    ❯ sleep 10000
    ^Z
    [1]  + 62750 suspended  sleep 10000
    ❯ bg
    [1]  + 62750 continued  sleep 10000
    ❯ pgrep sleep
    62750
    ❯ pkill -af sleep
    [1]  + 62750 terminated  sleep 10000
  2. 如果您希望某个进程结束后再开始另外一个进程, 应该如何实现呢?在这个练习中,我们使用 sleep 60 & 作为先执行的程序。一种方法是使用 wait 命令。尝试启动这个休眠命令,然后待其结束后再执行 ls 命令。

    ❯ sleep 10 &
    [3] 62850
    # wait 只能够等待当前 shell 的子进程
    ❯ wait 62850; ls
    [3]  + 62850 done       sleep 10
但是,如果我们在不同的 bash 会话中进行操作,则上述方法就不起作用了。因为 `wait` 只能对子进程起作用。之前我们没有提过的一个特性是,`kill` 命令成功退出时其状态码为 `0` ,其他状态则是非 `0`。`kill -0` 则不会发送信号,但是会在进程不存在时返回一个不为 `0` 的状态码。请编写一个 `bash` 函数 `pidwait` ,它接受一个 `pid` 作为输入参数,然后一直等待直到该进程结束。您需要使用 `sleep` 来避免浪费 `CPU` 性能。

`wait` 程序实现:
```bash
myWait() {
    pid=$1
    while true; do
        kill -0 $pid
        if [[ $? -eq 0 ]]; then
            echo "process exists, wait for 1 seconds..."
            sleep 1
        else
            break
        fi
    done
    echo "process finished!"
    ls
}
```
将程序保存为 `wait.sh` ,程序执行与结果:
```bash
❯ source wait.sh
❯ sleep 10
^Z
[1]  + 63612 suspended  sleep 10
❯ bg
[1]  + 63612 continued  sleep 10
❯ myWait 63612
process exists, wait for 1 seconds...
process exists, wait for 1 seconds...
process exists, wait for 1 seconds...
process exists, wait for 1 seconds...
process exists, wait for 1 seconds...
[1]  + 63612 done       sleep 10
myWait:kill:3: kill 63612 failed: no such process
process finished!
wait.sh
```

终端多路复用

  1. 请完成这个 tmux 教程:https://www.hamvocke.com/blog/a-quick-and-easy-guide-to-tmux/
  2. 参考这些步骤来学习如何自定义 tmux:https://www.hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/

    1. 配置文件位于:~/.tmux.conf
    2. 将前缀从 Ctrl+b 替换为 Ctrl+a,方便输入

      # remap prefix from 'C-b' to 'C-a'
      unbind C-b
      set-option -g prefix C-a
      bind-key C-a send-prefix
    3. 使用 | 将面板垂直分割,使用 - 将面板水平分割

      # split panes using | and -
      bind | split-window -h
      bind - split-window -v
      unbind '"'
      unbind %
    4. 更快捷地重载配置,使用 前缀+r

      # reload config file (change file location to your the tmux.conf you want to use)
      bind r source-file ~/.tmux.conf \; display-message "Config reloaded..."
    5. 更快捷地切换面板,使用 Alt 键加方向键来切换面板

      # switch panes using Alt-arrow without prefix
      bind -n M-Left select-pane -L
      bind -n M-Right select-pane -R
      bind -n M-Up select-pane -U
      bind -n M-Down select-pane -D
    6. 开启鼠标模式(不一定需要)

      # Enable mouse mode (tmux 2.1 and above)
      set -g mouse on
    7. 停止自动重命名窗口,通过 , 手动重命名,每个窗口可以执行不同的上下文

别名

  1. 创建一个 dc 别名,它的功能是当我们错误的将 cd 输入为 dc 时也能正确执行。

    alias dc="cd"
  2. 执行 history | awk '{$1="";print substr($0,2)}' | sort | uniq -c | sort -n | tail -n 10 来获取您最常用的十条命令,尝试为它们创建别名。注意:这个命令只在 Bash 中生效,如果您使用 ZSH,使用 history 1 替换 history

配置文件

让我们帮助您进一步学习配置文件:

  1. 为您的配置文件新建一个文件夹,并设置好版本控制
  2. 在其中添加至少一个配置文件,比如说您的 shell,在其中包含一些自定义设置(可以从设置 $PS1 开始)。
  3. 建立一种在新设备进行快速安装配置的方法(无需手动操作)。最简单的方法是写一个 shell 脚本对每个文件使用 ln -s,也可以使用专用工具
  4. 在新的虚拟机上测试该安装脚本。
  5. 将您现有的所有配置文件移动到项目仓库里。
  6. 将项目发布到 GitHub。

我将我的 tmuxvimzsh 的配置文件上传到了 GitHub,欢迎基于此进行修改:https://github.com/chris-algo/dotfiles 。


广告时间

如果您喜欢我的文章,欢迎给我点赞关注!也欢迎关注我的公众号:算法小哥克里斯。

计算机教育中缺失的一课

今天推荐一门值得你补上的课程。对于大部分计算机专业相关的学生,在学校中学习了大量的专业课程,从编程语言到操作系统甚至到机器学习,但你在实际做项目或者工作中,却会被一些使用工具上的问题难住,例如你学完编... 查看详情

shell工具和脚本:学习笔记

写在前面:本篇内容来自于MIT推出的课程:计算机教育中缺失的一课,这门课程介绍了命令行、强大的文本编辑器的使用、使用版本控制系统提供的多种特性等等。中文课程主页:https://missing-semester-cn.github.io/。本篇为学习第二... 查看详情

mit公开课:算法导论笔记

...sp;第一课算法分析总结解决问题的方法和方式算法:关于计算机程序性能和资源利用的研究算法:性能、速度在程序设计方面,什么比性能更重要呢?  正确性, 查看详情

批处理学习笔记第二十一课:数值计算

   批处理里面的数值计算功能较弱,只能够进行整型计算,忽略浮点数的小数部分;同时数值计算的范围也受限于系统位数,对于目前较为常见的32位机来说,数值计算能处理的数值范围为0x80000000h~0x7FFFFFFFh,即-2147483... 查看详情

命令行python和jupyter笔记本使用两个不同版本的手电筒(代码片段)

在我的conda环境中,从命令行python和jupyter笔记本导入火炬会产生两个不同的结果。从命令行中获得版本0.4.1(我想要的版本,在cuda91+上);从jupyter我得到1.2.0+cuda92。你知道我为什么得到这个吗?我从同一环境中调用python和jupyter... 查看详情

根据日期计算/分组行,包括缺失

】根据日期计算/分组行,包括缺失【英文标题】:Count/grouprowsbasedondateincludingmissing【发布时间】:2013-09-2510:57:56【问题描述】:我的数据库中有一堆表示订单的行,即id|date---------------------1|2013-09-012|2013-09-013|2013-09-024|2013-09-045|20... 查看详情

关于ide与环境变量的一点说明

环境变量就是当计算机要执行操作时,在环境变量所制定的范围内查找该操作。比如linux的ls命令,计算机就需要在$PATH规定的目录中寻找该ls的可执行文件。java的classpath,在该规定的目录中寻找class文件。JAVA_HOME,在该目录中寻找ja... 查看详情

大学计算机第一课

1.电子计算机概念  电子计算机(electroniccomputer),通称电脑,是计算机(computer)用途和数量都较广的一种,是现代的一种利用电子技术和相关原理根据一系列指令来对数据进行处理的机器。电脑可以分为两部分:软件系统... 查看详情

isight命令行运行任务

...ished.htm不一定对版本。但是大部分还可以。不对的可以在命令里敲help 首先,说明书里的命令行客户端默认加入环境变量。实测win/linux安装没有环境变量。可以自行添加也可找到目录自行运行 fipercmd== <Isight_ 查看详情

note.js笔记第一课

第一部分:环境安装   >1.下载安装nodejs       >01.http://www.nodejs.org/zh-cn/       >02.http://www.nodejs.org/en/  查看详情

mit6.828jos学习笔记16.lab2.2

Part3KernelAddressSpaceJOS把32位线性地址虚拟空间划分成两个部分。其中用户环境(进程运行环境)通常占据低地址的那部分,叫用户地址空间。而操作系统内核总是占据高地址的部分,叫内核地址空间。这两个部分的分界线是定义... 查看详情

将js进行到底:node学习笔记2

...行终端)。俗称“命令行程序”。计算机系学生c语言第一课 查看详情

编程序常用英语单词是啥

计算机编程序需要掌握的英文词汇,主要集中在代码调试阅读、变量、工具界面上,统计数据表明,只要掌握其中常用的500-600个词汇,就能够解决80%以上的问题。那么请问这500-600个单词是什么呢?1. architecture架构、系统架构... 查看详情

python怎么设置环境变量

...面上右击"此电脑",选择"属性",随后打开计算机属性窗口。02然后,点击"高级系统设置",再点击"环境变量"。03编辑系统变量中的环境变量Path,添加"%PYTHON_HOME%\\Scripts\\;%PYTHON_HOME%\\Python36\\;"... 查看详情

windowpowershell与命令提示符哪个好用

...很重要。现在能够断开远程会话,稍后能从同个或不同的计算机重新连接到相同的会话。客户端计算机崩溃的话,v3的社区技术预览版不能断开会话。相反,会话会永久关闭。所以这与远程桌面完全不同,远程桌面会话能在客户... 查看详情

如何在windows的命令行环境下编译c++程序?

...本人安装的VisualStudio2012第二步:设置环境变量1)右键“计算机(我的电脑)”,选择“属性->高级系统设置->环境变量”,找到“系统变量”中的“PATH"属性,双击之2)复制VisualStudio安装目录下的路径“D:\ProgramFiles(x8... 查看详情

python基础2022最新第一课安装&环境配置(代码片段)

...置windows在命令提示框输入:path=%path%;C:\\Python手动配置:计算机->属性->高级系统设置PyCharm安装PyCharm官网下载社区版:双击安装:创建项目:新建pyt 查看详情

cmd命令行提示不是内部或外部命令怎么办

...提示不是内部或外部命令的解决方法  右键点击桌面【计算机】图标,在弹出的菜单栏选择【属性】选项  进入系统属性界面,点击左侧的【高级系统设置】选项  进入系统属性对话框,点击选择上方【高级】选项  进... 查看详情